diff --git a/examples/Demo/Shared/Microsoft.FluentUI.AspNetCore.Components.xml b/examples/Demo/Shared/Microsoft.FluentUI.AspNetCore.Components.xml index 005c8155b7..917e69feaf 100644 --- a/examples/Demo/Shared/Microsoft.FluentUI.AspNetCore.Components.xml +++ b/examples/Demo/Shared/Microsoft.FluentUI.AspNetCore.Components.xml @@ -13011,12 +13011,17 @@ - FluentUI System Icon font size 10x10 + Filled variant of FluentUI System Icons - FluentUI System Icon font size 12x12 + Regular variant of FluentUI System Icons + + + + + Light variant of FluentUI System Icons @@ -14291,6 +14296,13 @@ By default, the tooltip closes if the cursor leaves the anchor, but not the tooltip itself. + + + Gets or sets the value indicating whether the library should validate CSS class names. + respecting the following regex: "^-?[_a-zA-Z]+[_a-zA-Z0-9-]*$". + Default is true. + + A strongly-typed resource class, for looking up localized strings, etc. @@ -14367,11 +14379,22 @@ Looks up a localized string similar to {0} years ago. + + + Validate CSS class, which must respect the following regex: "^-?[_a-zA-Z]+[_a-zA-Z0-9-]*$". + Default is true. + + Initializes a new instance of the class. + + + Initializes a new instance of the class. + + Initializes a new instance of the class. diff --git a/examples/Demo/Shared/wwwroot/docs/CodeSetup.md b/examples/Demo/Shared/wwwroot/docs/CodeSetup.md index c16bb729ad..cfcb405869 100644 --- a/examples/Demo/Shared/wwwroot/docs/CodeSetup.md +++ b/examples/Demo/Shared/wwwroot/docs/CodeSetup.md @@ -49,6 +49,23 @@ When using **SSR (Static Server Rendering)**, you will need to include the web c ``` If you would later add interactivity, the Blazor script will kick in and try to load the web component script again but JavaScript will handle that gracefully by design. +### Styles + +The styles used by FluentUI are included in the package. +You don't need to do anything to include them in your project. + +You can always add your own styles, using the `class` or `style` attribute on the components. +By default, the classes are organised and checked by the component itself (in particular by checking that the class names are valid). +Some frameworks, such as **Tailwind CSS**, add exceptions to class names (e.g. `min-h-[16px]` or `bg-[#ff0000]`). +In this case, you need to disable class name validation by adding this code to your `Program.cs` file: + +```csharp +builder.Services.AddFluentUIComponents(options => +{ + options.ValidateClassNames = false; +}); +``` + ### Reboot (optional) **Reboot** is a collection of element-specific CSS changes in a single file to help kick-start building a site with the **Fluent UI Blazor** components for Blazor. It provides an elegant, consistent, and simple baseline to build upon. diff --git a/src/Core/Infrastructure/LibraryConfiguration.cs b/src/Core/Infrastructure/LibraryConfiguration.cs index 00d375a65a..6547a2b168 100644 --- a/src/Core/Infrastructure/LibraryConfiguration.cs +++ b/src/Core/Infrastructure/LibraryConfiguration.cs @@ -29,6 +29,17 @@ public class LibraryConfiguration /// public bool HideTooltipOnCursorLeave { get; set; } = false; + /// + /// Gets or sets the value indicating whether the library should validate CSS class names. + /// respecting the following regex: "^-?[_a-zA-Z]+[_a-zA-Z0-9-]*$". + /// Default is true. + /// + public bool ValidateClassNames + { + get => Utilities.CssBuilder.ValidateClassNames; + set => Utilities.CssBuilder.ValidateClassNames = value; + } + public LibraryConfiguration() { } diff --git a/src/Core/Utilities/CssBuilder.cs b/src/Core/Utilities/CssBuilder.cs index 775d24bb97..5e116e9a9b 100644 --- a/src/Core/Utilities/CssBuilder.cs +++ b/src/Core/Utilities/CssBuilder.cs @@ -8,6 +8,14 @@ public readonly partial struct CssBuilder private readonly string[]? _userClasses; private static readonly Regex ValidClassNameRegex = GenerateValidClassNameRegex(); + /// + /// Validate CSS class, which must respect the following regex: "^-?[_a-zA-Z]+[_a-zA-Z0-9-]*$". + /// Default is true. + /// + public static bool ValidateClassNames = true; + + private readonly bool _validateClassNames = ValidateClassNames; + /// /// Initializes a new instance of the class. /// @@ -17,6 +25,14 @@ public CssBuilder() _userClasses = null; } + /// + /// Initializes a new instance of the class. + /// + internal CssBuilder(bool validateClassNames, string? userClasses) : this(userClasses) + { + _validateClassNames = validateClassNames; + } + /// /// Initializes a new instance of the class. /// @@ -84,9 +100,9 @@ public CssBuilder AddClass(string? values) /// /// CSS class name to validate /// True if valid, otherwise false - private static bool IsValidClassName(string className) + private bool IsValidClassName(string className) { - return ValidClassNameRegex.IsMatch(className); + return _validateClassNames ? ValidClassNameRegex.IsMatch(className) : true; } /// @@ -94,7 +110,7 @@ private static bool IsValidClassName(string className) /// /// Space-separated CSS Classes /// Enumerable of valid class names - private static IEnumerable SplitAndValidate(string input) + private IEnumerable SplitAndValidate(string input) { return input.Split(' ', StringSplitOptions.RemoveEmptyEntries).Where(IsValidClassName); } diff --git a/tests/Core/Utilities/CssBuilderTests.cs b/tests/Core/Utilities/CssBuilderTests.cs index 7c87845195..3f38b8359c 100644 --- a/tests/Core/Utilities/CssBuilderTests.cs +++ b/tests/Core/Utilities/CssBuilderTests.cs @@ -179,4 +179,25 @@ public void CssBuilder_CombinesValidUserAndAddedClasses() // Assert Assert.Equal("added-class user-class", cssBuilder.Build()); } + + [Theory] + [InlineData("min-h-[16px] user-class", "min-h-[16px] ")] + [InlineData("bg-red-500/50 user-class", " bg-red-500/50")] + [InlineData("bg-[#ff0000] user-class", " bg-[#ff0000] ")] + [InlineData("a:hover user-class", "a:hover")] + [InlineData("min-h-[16px] a:hover user-class", "min-h-[16px]", "a:hover")] + public void CssBuilder_ValidateClassNames_AcceptInvalid(string expected, params string[] value) + { + // Arrange + var cssBuilder = new CssBuilder(validateClassNames: false, userClasses: "user-class"); + + // Act + foreach (var item in value) + { + cssBuilder.AddClass(item); + } + + // Assert + Assert.Equal(expected, cssBuilder.Build()); + } }