From 9d9885b8c207d2307cf2a6c472c5f18954010c05 Mon Sep 17 00:00:00 2001 From: phmatray Date: Thu, 5 Mar 2026 10:22:55 +0100 Subject: [PATCH] fix: resolve package compatibility and MudBlazor v9 breaking changes - Fix Directory.Packages.props: use TFM-appropriate Microsoft package versions (8.0.x for net8.0, 9.0.x for net9.0, 10.0.x for net10.0) instead of 10.0.3 across all targets (Renovate bot error) - Migrate MudFileUpload ActivatorContent to CustomContent (MudBlazor v9) - Remove obsolete InputStyle, move opacity to InputClass - Update ServerDataFunc signature with CancellationToken parameter - Move PanelClass from MudTabs to MudTabPanel (MudBlazor v9 API change) - Replace removed SetText() with ValueChanged.InvokeAsync() in tests - Suppress MUD0012 analyzer in test projects for .Value assertions Co-Authored-By: Claude Opus 4.6 --- Directory.Packages.props | 28 +++++++++---------- .../Components/Pages/TabbedForm.razor | 16 +++++++---- .../Components/Shared/DemoPageLayout.razor | 8 +++--- .../Components/Shared/FeatureShowcase.razor | 10 +++---- .../MudBlazorTextFieldComponentTests.cs | 24 ++++++++-------- .../FormCraft.ForMudBlazor.UnitTests.csproj | 2 +- .../FormContainer/FormCraftComponent.razor.cs | 2 +- .../MudBlazorFileUploadFieldComponent.razor | 7 ++--- ...MudBlazorMultipleFileUploadComponent.razor | 7 ++--- .../LovField/LovSelectionDialog.razor.cs | 2 +- .../ForMudBlazor/PasswordFieldTests.cs | 6 ++-- .../FormCraft.UnitTests.csproj | 2 +- 12 files changed, 58 insertions(+), 56 deletions(-) diff --git a/Directory.Packages.props b/Directory.Packages.props index 8b41200..2c5b89f 100644 --- a/Directory.Packages.props +++ b/Directory.Packages.props @@ -31,23 +31,23 @@ - - - - - - - + + + + + + + - - - - - - - + + + + + + + diff --git a/FormCraft.DemoBlazorApp/Components/Pages/TabbedForm.razor b/FormCraft.DemoBlazorApp/Components/Pages/TabbedForm.razor index 41c4252..c1702fb 100644 --- a/FormCraft.DemoBlazorApp/Components/Pages/TabbedForm.razor +++ b/FormCraft.DemoBlazorApp/Components/Pages/TabbedForm.razor @@ -26,9 +26,10 @@ Elevation="2" Rounded="true" ApplyEffectsToContainer="true" - PanelClass="pa-4"> + > - - - + + @FormDemoContent - + @CodeExampleContent - + @GuidelinesContent diff --git a/FormCraft.DemoBlazorApp/Components/Shared/FeatureShowcase.razor b/FormCraft.DemoBlazorApp/Components/Shared/FeatureShowcase.razor index 4af9a8b..d771233 100644 --- a/FormCraft.DemoBlazorApp/Components/Shared/FeatureShowcase.razor +++ b/FormCraft.DemoBlazorApp/Components/Shared/FeatureShowcase.razor @@ -10,8 +10,8 @@ - + ApplyEffectsToContainer="true"> + Try Invalid Input @@ -45,7 +45,7 @@ - + Cascading Fields @@ -67,7 +67,7 @@ - + Various Input Types @@ -94,7 +94,7 @@ - + Flexible Layouts diff --git a/FormCraft.ForMudBlazor.UnitTests/Fields/MudBlazorTextFieldComponentTests.cs b/FormCraft.ForMudBlazor.UnitTests/Fields/MudBlazorTextFieldComponentTests.cs index f728c4c..cdf8c5c 100644 --- a/FormCraft.ForMudBlazor.UnitTests/Fields/MudBlazorTextFieldComponentTests.cs +++ b/FormCraft.ForMudBlazor.UnitTests/Fields/MudBlazorTextFieldComponentTests.cs @@ -278,7 +278,7 @@ public async Task TextField_Should_Update_Model_On_Input() mudTextField.ShouldNotBeNull(); // Act - await mudTextField.InvokeAsync(() => mudTextField.Instance.SetText("John Doe")); + await mudTextField.InvokeAsync(() => mudTextField.Instance.ValueChanged.InvokeAsync("John Doe")); // Assert model.Name.ShouldBe("John Doe"); @@ -328,11 +328,11 @@ public async Task TextField_Should_Preserve_Value_After_Multiple_Inputs() var mudTextField = component.FindComponent>(); // Act - Simulate typing character by character - await mudTextField.InvokeAsync(() => mudTextField.Instance.SetText("H")); - await mudTextField.InvokeAsync(() => mudTextField.Instance.SetText("He")); - await mudTextField.InvokeAsync(() => mudTextField.Instance.SetText("Hel")); - await mudTextField.InvokeAsync(() => mudTextField.Instance.SetText("Hell")); - await mudTextField.InvokeAsync(() => mudTextField.Instance.SetText("Hello")); + await mudTextField.InvokeAsync(() => mudTextField.Instance.ValueChanged.InvokeAsync("H")); + await mudTextField.InvokeAsync(() => mudTextField.Instance.ValueChanged.InvokeAsync("He")); + await mudTextField.InvokeAsync(() => mudTextField.Instance.ValueChanged.InvokeAsync("Hel")); + await mudTextField.InvokeAsync(() => mudTextField.Instance.ValueChanged.InvokeAsync("Hell")); + await mudTextField.InvokeAsync(() => mudTextField.Instance.ValueChanged.InvokeAsync("Hello")); // Assert model.Name.ShouldBe("Hello"); @@ -359,7 +359,7 @@ public async Task PasswordField_Should_Update_Model_On_Input() mudTextField.ShouldNotBeNull(); // Act - await mudTextField.InvokeAsync(() => mudTextField.Instance.SetText("secret123")); + await mudTextField.InvokeAsync(() => mudTextField.Instance.ValueChanged.InvokeAsync("secret123")); // Assert model.Password.ShouldBe("secret123"); @@ -384,10 +384,10 @@ public async Task PasswordField_Should_Preserve_Value_After_Multiple_Inputs() var mudTextField = component.FindComponent>(); // Act - Simulate typing character by character - await mudTextField.InvokeAsync(() => mudTextField.Instance.SetText("p")); - await mudTextField.InvokeAsync(() => mudTextField.Instance.SetText("pa")); - await mudTextField.InvokeAsync(() => mudTextField.Instance.SetText("pas")); - await mudTextField.InvokeAsync(() => mudTextField.Instance.SetText("pass")); + await mudTextField.InvokeAsync(() => mudTextField.Instance.ValueChanged.InvokeAsync("p")); + await mudTextField.InvokeAsync(() => mudTextField.Instance.ValueChanged.InvokeAsync("pa")); + await mudTextField.InvokeAsync(() => mudTextField.Instance.ValueChanged.InvokeAsync("pas")); + await mudTextField.InvokeAsync(() => mudTextField.Instance.ValueChanged.InvokeAsync("pass")); // Assert model.Password.ShouldBe("pass"); @@ -412,7 +412,7 @@ public async Task TextField_Value_Should_Reflect_In_Component_After_Update() var mudTextField = component.FindComponent>(); // Act - await mudTextField.InvokeAsync(() => mudTextField.Instance.SetText("Updated")); + await mudTextField.InvokeAsync(() => mudTextField.Instance.ValueChanged.InvokeAsync("Updated")); // Re-render to ensure component state is synced component.Render(); diff --git a/FormCraft.ForMudBlazor.UnitTests/FormCraft.ForMudBlazor.UnitTests.csproj b/FormCraft.ForMudBlazor.UnitTests/FormCraft.ForMudBlazor.UnitTests.csproj index 6669f90..d5df01c 100644 --- a/FormCraft.ForMudBlazor.UnitTests/FormCraft.ForMudBlazor.UnitTests.csproj +++ b/FormCraft.ForMudBlazor.UnitTests/FormCraft.ForMudBlazor.UnitTests.csproj @@ -8,7 +8,7 @@ net10.0 true true - $(NoWarn);BL0005 + $(NoWarn);BL0005;MUD0012 diff --git a/FormCraft.ForMudBlazor/Features/FormContainer/FormCraftComponent.razor.cs b/FormCraft.ForMudBlazor/Features/FormContainer/FormCraftComponent.razor.cs index 577900d..f47078c 100644 --- a/FormCraft.ForMudBlazor/Features/FormContainer/FormCraftComponent.razor.cs +++ b/FormCraft.ForMudBlazor/Features/FormContainer/FormCraftComponent.razor.cs @@ -265,7 +265,7 @@ private void RenderFileUploadField(RenderTreeBuilder builder, IFieldConfiguratio builder.AddAttribute(2, "Accept", field.AdditionalAttributes.GetValueOrDefault("Accept", "*/*")); builder.AddAttribute(3, "Disabled", field.IsDisabled); - builder.AddAttribute(4, "ActivatorContent", RenderFileUploadButton(field)); + builder.AddAttribute(4, "CustomContent", RenderFileUploadButton(field)); builder.CloseComponent(); } diff --git a/FormCraft.ForMudBlazor/Fields/FileUploadField/MudBlazorFileUploadFieldComponent.razor b/FormCraft.ForMudBlazor/Fields/FileUploadField/MudBlazorFileUploadFieldComponent.razor index 74dbe4f..26c98e0 100644 --- a/FormCraft.ForMudBlazor/Fields/FileUploadField/MudBlazorFileUploadFieldComponent.razor +++ b/FormCraft.ForMudBlazor/Fields/FileUploadField/MudBlazorFileUploadFieldComponent.razor @@ -15,15 +15,14 @@ Accept="@Accept" MaximumFileCount="1" Hidden="@false" - InputClass="absolute mud-width-full mud-height-full overflow-hidden z-10" - InputStyle="opacity:0" + InputClass="absolute mud-width-full mud-height-full overflow-hidden z-10 opacity-0" ErrorText="@string.Empty" tabindex="-1" @ondrop="@ClearDragClass" @ondragenter="@SetDragClass" @ondragleave="@ClearDragClass" @ondragend="@ClearDragClass"> - + - + diff --git a/FormCraft.ForMudBlazor/Fields/FileUploadField/MudBlazorMultipleFileUploadComponent.razor b/FormCraft.ForMudBlazor/Fields/FileUploadField/MudBlazorMultipleFileUploadComponent.razor index 48ffda7..f77298b 100644 --- a/FormCraft.ForMudBlazor/Fields/FileUploadField/MudBlazorMultipleFileUploadComponent.razor +++ b/FormCraft.ForMudBlazor/Fields/FileUploadField/MudBlazorMultipleFileUploadComponent.razor @@ -13,15 +13,14 @@ Accept="@Accept" MaximumFileCount="@MaxFiles" Hidden="@false" - InputClass="absolute mud-width-full mud-height-full overflow-hidden z-10" - InputStyle="opacity:0" + InputClass="absolute mud-width-full mud-height-full overflow-hidden z-10 opacity-0" ErrorText="@string.Empty" tabindex="-1" @ondrop="@ClearDragClass" @ondragenter="@SetDragClass" @ondragleave="@ClearDragClass" @ondragend="@ClearDragClass"> - + @@ -61,7 +60,7 @@ } - + diff --git a/FormCraft.ForMudBlazor/Fields/LovField/LovSelectionDialog.razor.cs b/FormCraft.ForMudBlazor/Fields/LovField/LovSelectionDialog.razor.cs index d0dd9db..bd21d6d 100644 --- a/FormCraft.ForMudBlazor/Fields/LovField/LovSelectionDialog.razor.cs +++ b/FormCraft.ForMudBlazor/Fields/LovField/LovSelectionDialog.razor.cs @@ -67,7 +67,7 @@ protected override void OnInitialized() /// /// Server data callback for MudDataGrid virtualization. /// - private async Task> ServerDataFunc(GridState gridState) + private async Task> ServerDataFunc(GridState gridState, CancellationToken cancellationToken) { if (DataProvider == null) { diff --git a/FormCraft.UnitTests/ForMudBlazor/PasswordFieldTests.cs b/FormCraft.UnitTests/ForMudBlazor/PasswordFieldTests.cs index a73b78a..d6ad381 100644 --- a/FormCraft.UnitTests/ForMudBlazor/PasswordFieldTests.cs +++ b/FormCraft.UnitTests/ForMudBlazor/PasswordFieldTests.cs @@ -188,7 +188,7 @@ public async Task Password_Field_Should_Update_Model_When_User_Types() // Act - Simulate user typing in the password field by invoking ValueChanged mudTextField.Instance.Value.ShouldBe(""); // Initially empty - await mudTextField.InvokeAsync(() => mudTextField.Instance.SetText("MySecretPassword123")); + await mudTextField.InvokeAsync(() => mudTextField.Instance.ValueChanged.InvokeAsync("MySecretPassword123")); // Assert - Model should be updated with the new value model.Password.ShouldBe("MySecretPassword123"); @@ -215,7 +215,7 @@ public async Task Email_Field_Should_Update_Model_When_User_Types() // Act - Simulate user typing in the email field mudTextField.Instance.Value.ShouldBe(""); // Initially empty - await mudTextField.InvokeAsync(() => mudTextField.Instance.SetText("user@example.com")); + await mudTextField.InvokeAsync(() => mudTextField.Instance.ValueChanged.InvokeAsync("user@example.com")); // Assert - Model should be updated with the new value model.Email.ShouldBe("user@example.com"); @@ -241,7 +241,7 @@ public async Task Username_Field_Should_Update_Model_When_User_Types() // Act - Simulate user typing mudTextField.Instance.Value.ShouldBe(""); // Initially empty - await mudTextField.InvokeAsync(() => mudTextField.Instance.SetText("john_doe")); + await mudTextField.InvokeAsync(() => mudTextField.Instance.ValueChanged.InvokeAsync("john_doe")); // Assert - Model should be updated model.Username.ShouldBe("john_doe"); diff --git a/FormCraft.UnitTests/FormCraft.UnitTests.csproj b/FormCraft.UnitTests/FormCraft.UnitTests.csproj index 229367b..2c7463e 100644 --- a/FormCraft.UnitTests/FormCraft.UnitTests.csproj +++ b/FormCraft.UnitTests/FormCraft.UnitTests.csproj @@ -8,7 +8,7 @@ net10.0 true true - $(NoWarn);BL0005 + $(NoWarn);BL0005;MUD0012