Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -13011,12 +13011,17 @@
</member>
<member name="F:Microsoft.FluentUI.AspNetCore.Components.IconVariant.Filled">
<summary>
FluentUI System Icon font size 10x10
Filled variant of FluentUI System Icons
</summary>
</member>
<member name="F:Microsoft.FluentUI.AspNetCore.Components.IconVariant.Regular">
<summary>
FluentUI System Icon font size 12x12
Regular variant of FluentUI System Icons
</summary>
</member>
<member name="F:Microsoft.FluentUI.AspNetCore.Components.IconVariant.Light">
<summary>
Light variant of FluentUI System Icons
</summary>
</member>
<member name="T:Microsoft.FluentUI.AspNetCore.Components.InputFileMode">
Expand Down Expand Up @@ -14291,6 +14296,13 @@
By default, the tooltip closes if the cursor leaves the anchor, but not the tooltip itself.
</summary>
</member>
<member name="P:Microsoft.FluentUI.AspNetCore.Components.LibraryConfiguration.ValidateClassNames">
<summary>
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.
</summary>
</member>
<member name="T:Microsoft.FluentUI.AspNetCore.Components.Resources.TimeAgoResource">
<summary>
A strongly-typed resource class, for looking up localized strings, etc.
Expand Down Expand Up @@ -14367,11 +14379,22 @@
Looks up a localized string similar to {0} years ago.
</summary>
</member>
<member name="F:Microsoft.FluentUI.AspNetCore.Components.Utilities.CssBuilder.ValidateClassNames">
<summary>
Validate CSS class, which must respect the following regex: "^-?[_a-zA-Z]+[_a-zA-Z0-9-]*$".
Default is true.
</summary>
</member>
<member name="M:Microsoft.FluentUI.AspNetCore.Components.Utilities.CssBuilder.#ctor">
<summary>
Initializes a new instance of the <see cref="T:Microsoft.FluentUI.AspNetCore.Components.Utilities.CssBuilder"/> class.
</summary>
</member>
<member name="M:Microsoft.FluentUI.AspNetCore.Components.Utilities.CssBuilder.#ctor(System.Boolean,System.String)">
<summary>
Initializes a new instance of the <see cref="T:Microsoft.FluentUI.AspNetCore.Components.Utilities.CssBuilder"/> class.
</summary>
</member>
<member name="M:Microsoft.FluentUI.AspNetCore.Components.Utilities.CssBuilder.#ctor(System.String)">
<summary>
Initializes a new instance of the <see cref="T:Microsoft.FluentUI.AspNetCore.Components.Utilities.CssBuilder"/> class.
Expand Down
17 changes: 17 additions & 0 deletions examples/Demo/Shared/wwwroot/docs/CodeSetup.md
Original file line number Diff line number Diff line change
Expand Up @@ -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.

Expand Down
11 changes: 11 additions & 0 deletions src/Core/Infrastructure/LibraryConfiguration.cs
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,17 @@ public class LibraryConfiguration
/// </summary>
public bool HideTooltipOnCursorLeave { get; set; } = false;

/// <summary>
/// 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.
/// </summary>
public bool ValidateClassNames
{
get => Utilities.CssBuilder.ValidateClassNames;
set => Utilities.CssBuilder.ValidateClassNames = value;
}

public LibraryConfiguration()
{
}
Expand Down
22 changes: 19 additions & 3 deletions src/Core/Utilities/CssBuilder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,14 @@ public readonly partial struct CssBuilder
private readonly string[]? _userClasses;
private static readonly Regex ValidClassNameRegex = GenerateValidClassNameRegex();

/// <summary>
/// Validate CSS class, which must respect the following regex: "^-?[_a-zA-Z]+[_a-zA-Z0-9-]*$".
/// Default is true.
/// </summary>
public static bool ValidateClassNames = true;

private readonly bool _validateClassNames = ValidateClassNames;

/// <summary>
/// Initializes a new instance of the <see cref="CssBuilder"/> class.
/// </summary>
Expand All @@ -17,6 +25,14 @@ public CssBuilder()
_userClasses = null;
}

/// <summary>
/// Initializes a new instance of the <see cref="CssBuilder"/> class.
/// </summary>
internal CssBuilder(bool validateClassNames, string? userClasses) : this(userClasses)
{
_validateClassNames = validateClassNames;
}

/// <summary>
/// Initializes a new instance of the <see cref="CssBuilder"/> class.
/// </summary>
Expand Down Expand Up @@ -84,17 +100,17 @@ public CssBuilder AddClass(string? values)
/// </summary>
/// <param name="className">CSS class name to validate</param>
/// <returns>True if valid, otherwise false</returns>
private static bool IsValidClassName(string className)
private bool IsValidClassName(string className)
{
return ValidClassNameRegex.IsMatch(className);
return _validateClassNames ? ValidClassNameRegex.IsMatch(className) : true;
}

/// <summary>
/// Splits a space-separated string of class names and validates each one.
/// </summary>
/// <param name="input">Space-separated CSS Classes</param>
/// <returns>Enumerable of valid class names</returns>
private static IEnumerable<string> SplitAndValidate(string input)
private IEnumerable<string> SplitAndValidate(string input)
{
return input.Split(' ', StringSplitOptions.RemoveEmptyEntries).Where(IsValidClassName);
}
Expand Down
21 changes: 21 additions & 0 deletions tests/Core/Utilities/CssBuilderTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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());
}
}