From 4411140ee046d8d742f78168a8af03d78b119af6 Mon Sep 17 00:00:00 2001 From: MarvinKlein1508 Date: Thu, 27 Nov 2025 10:09:22 +0100 Subject: [PATCH 01/36] Copy component from v4 --- .../Components/Overlay/FluentOverlay.razor | 16 + .../Components/Overlay/FluentOverlay.razor.cs | 289 ++++++++++++++++++ .../Overlay/FluentOverlay.razor.css | 8 + ...soft.FluentUI.AspNetCore.Components.csproj | 2 +- src/Core/Utilities/ZIndex.cs | 5 + 5 files changed, 319 insertions(+), 1 deletion(-) create mode 100644 src/Core/Components/Overlay/FluentOverlay.razor create mode 100644 src/Core/Components/Overlay/FluentOverlay.razor.cs create mode 100644 src/Core/Components/Overlay/FluentOverlay.razor.css diff --git a/src/Core/Components/Overlay/FluentOverlay.razor b/src/Core/Components/Overlay/FluentOverlay.razor new file mode 100644 index 0000000000..a47ba27b23 --- /dev/null +++ b/src/Core/Components/Overlay/FluentOverlay.razor @@ -0,0 +1,16 @@ +@namespace Microsoft.FluentUI.AspNetCore.Components +@inherits FluentComponentBase + +@if (Visible) +{ +
+
+ @ChildContent +
+
+} diff --git a/src/Core/Components/Overlay/FluentOverlay.razor.cs b/src/Core/Components/Overlay/FluentOverlay.razor.cs new file mode 100644 index 0000000000..9e8f3eefd0 --- /dev/null +++ b/src/Core/Components/Overlay/FluentOverlay.razor.cs @@ -0,0 +1,289 @@ +// ------------------------------------------------------------------------ +// This file is licensed to you under the MIT License. +// ------------------------------------------------------------------------ + +using System.Globalization; +using System.Text.RegularExpressions; +using Microsoft.AspNetCore.Components; +using Microsoft.AspNetCore.Components.Web; +using Microsoft.FluentUI.AspNetCore.Components.Extensions; +using Microsoft.FluentUI.AspNetCore.Components.Utilities; +using Microsoft.JSInterop; + +namespace Microsoft.FluentUI.AspNetCore.Components; + +/// +public partial class FluentOverlay : FluentComponentBase, IAsyncDisposable +{ + private readonly string _defaultId = Identifier.NewId(); + private string? _color; + private int _r, _g, _b; + + //private const string JAVASCRIPT_FILE = "./_content/Microsoft.FluentUI.AspNetCore.Components/Components/Overlay/FluentOverlay.razor.js"; + private const string DEFAULT_NEUTRAL_COLOR = "#808080"; + + private DotNetObjectReference? _dotNetHelper; + + /// + public FluentOverlay(LibraryConfiguration configuration) : base(configuration) { } + + /// + private IJSObjectReference? _jsModule { get; set; } + + /// + protected string? ClassValue => new CssBuilder("fluent-overlay") + .AddClass("prevent-scroll", PreventScroll) + .Build(); + + /// + protected string? StyleValue => new StyleBuilder() + .AddStyle("cursor", "auto", () => Transparent) + //.AddStyle("background-color", $"rgba({_r}, {_g}, {_b}, {Opacity.ToString()})", () => !Transparent) + ////.AddStyle("opacity", Opacity.ToString()!.Replace(',', '.'), CheckCSSVariableName().IsMatch(BackgroundColor)) + .AddStyle("cursor", "default", () => !Transparent) + .AddStyle("position", FullScreen ? "fixed" : "absolute") + .AddStyle("display", "flex") + .AddStyle("align-items", Alignment.ToAttributeValue()) + .AddStyle("justify-content", Justification.ToAttributeValue()) + .AddStyle("pointer-events", "none", () => Interactive) + .AddStyle("z-index", ZIndex.Overlay.ToString(CultureInfo.InvariantCulture)) + .Build(); + + /// + protected string? StyleContentValue => new StyleBuilder() + .AddStyle("pointer-events", "auto", () => Interactive) + .Build(); + + /// + /// Gets or sets a value indicating whether the overlay is visible. + /// + [Parameter] + public bool Visible { get; set; } = false; + + /// + /// Callback for when overlay visibility changes. + /// + [Parameter] + public EventCallback VisibleChanged { get; set; } + + /// + /// Callback for when the overlay is closed. + /// + [Parameter] + public EventCallback OnClose { get; set; } + + /// + /// Gets or set if the overlay is transparent. + /// + [Parameter] + public bool Transparent { get; set; } = true; + + /// + /// Gets or sets the opacity of the overlay. + /// Default is 0.4. + /// + [Parameter] + public double? Opacity { get; set; } + + /// + /// Gets or sets the alignment of the content to a value. + /// Defaults to Align.Center. + /// + [Parameter] + public HorizontalAlignment Alignment { get; set; } = HorizontalAlignment.Center; + + /// + /// Gets or sets the justification of the content to a value. + /// Defaults to JustifyContent.Center. + /// + [Parameter] + public JustifyContent Justification { get; set; } = JustifyContent.Center; + + /// + /// Gets or sets a value indicating whether the overlay is shown full screen or bound to the containing element. + /// + [Parameter] + public bool FullScreen { get; set; } = false; + + /// + /// Gets or sets a value indicating whether the overlay is interactive, except for the element with the specified . + /// In other words, the elements below the overlay remain usable (mouse-over, click) and the overlay will closed when clicked. + /// + [Parameter] + public bool Interactive { get; set; } = false; + + /// + /// Gets or sets the HTML identifier of the element that is not interactive when the overlay is shown. + /// This property is ignored if is false. + /// + [Parameter] + public string? InteractiveExceptId { get; set; } = null; + + /// + /// Gets of sets a value indicating if the overlay can be dismissed by clicking on it. + /// Default is true. + /// + [Parameter] + public bool Dismissable { get; set; } = true; + + /// + /// Gets or sets the background color. + /// Needs to be formatted as an HTML hex color string (#rrggbb or #rgb) + /// Default NeutralBaseColor token value (#808080). + /// + [Parameter] + public string? BackgroundColor { get; set; } + + /// + [Parameter] + public bool PreventScroll { get; set; } = false; + + /// + [Parameter] + public RenderFragment? ChildContent { get; set; } + + /// + protected override async Task OnParametersSetAsync() + { + if (Interactive) + { + if (string.IsNullOrEmpty(Id)) + { + Id = _defaultId; + } + + if (Visible) + { + // Add a document.addEventListener when Visible is true + await InvokeOverlayInitializeAsync(); + } + else + { + // Remove a document.addEventListener when Visible is false + await InvokeOverlayDisposeAsync(); + } + } + + if (!Transparent && Opacity is null) + { + Opacity = 0.4; + } + + if (Opacity > 0) + { + Transparent = false; + } + + BackgroundColor ??= DEFAULT_NEUTRAL_COLOR;//GlobalState.NeutralColor ?? DEFAULT_NEUTRAL_COLOR; + + if (!CheckRGBString().IsMatch(BackgroundColor)) + { + throw new ArgumentException("BackgroundColor must be a valid HTML hex color string (#rrggbb or #rgb)"); + } + + _color = BackgroundColor[1..]; + + if (_color.Length == 6) + { + _r = int.Parse(_color[..2], NumberStyles.HexNumber, CultureInfo.InvariantCulture); + _g = int.Parse(_color[2..4], NumberStyles.HexNumber, CultureInfo.InvariantCulture); + _b = int.Parse(_color[4..], NumberStyles.HexNumber, CultureInfo.InvariantCulture); + } + else + { + _r = int.Parse(_color[0..1], NumberStyles.HexNumber, CultureInfo.InvariantCulture); + _g = int.Parse(_color[1..2], NumberStyles.HexNumber, CultureInfo.InvariantCulture); + _b = int.Parse(_color[2..], NumberStyles.HexNumber, CultureInfo.InvariantCulture); + } + } + + /// + [JSInvokable] + public async Task OnCloseInteractiveAsync(MouseEventArgs e) + { + if (!Dismissable || !Visible) + { + return; + } + + // Remove the document.removeEventListener + await InvokeOverlayDisposeAsync(); + + // Close the overlay + await OnCloseInternalHandlerAsync(e); + } + + /// + public async Task OnCloseHandlerAsync(MouseEventArgs e) + { + if (!Dismissable || !Visible || Interactive) + { + return; + } + + // Close the overlay + await OnCloseInternalHandlerAsync(e); + } + + private async Task OnCloseInternalHandlerAsync(MouseEventArgs e) + { + Visible = false; + + if (VisibleChanged.HasDelegate) + { + await VisibleChanged.InvokeAsync(Visible); + } + + if (OnClose.HasDelegate) + { + await OnClose.InvokeAsync(e); + } + } + + /// + /// Disposes the overlay. + /// + /// + public override async ValueTask DisposeAsync() + { + await base.DisposeAsync(); + + try + { + await InvokeOverlayDisposeAsync(); + + if (_jsModule != null) + { + await _jsModule.DisposeAsync(); + } + } + catch (Exception ex) when (ex is JSDisconnectedException || + ex is OperationCanceledException) + { + // The JSRuntime side may routinely be gone already if the reason we're disposing is that + // the client disconnected. This is not an error. + } + } + + /// + private async Task InvokeOverlayInitializeAsync() + { + _dotNetHelper ??= DotNetObjectReference.Create(this); + //_jsModule ??= await JSRuntime.InvokeAsync("import", JAVASCRIPT_FILE.FormatCollocatedUrl(LibraryConfiguration)); + + //var containerId = FullScreen ? null : Id; + //await _jsModule.InvokeVoidAsync("overlayInitialize", _dotNetHelper, containerId, InteractiveExceptId); + } + + /// + private async Task InvokeOverlayDisposeAsync() + { + if (_jsModule != null && Interactive) + { + await _jsModule.InvokeVoidAsync("overlayDispose", InteractiveExceptId); + } + } + + [GeneratedRegex("^(?:#(?:[a-fA-F0-9]{6}|[a-fA-F0-9]{3}))", RegexOptions.None, matchTimeoutMilliseconds: 1000)] //Add timeout to prevent ReDoS + private static partial Regex CheckRGBString(); +} diff --git a/src/Core/Components/Overlay/FluentOverlay.razor.css b/src/Core/Components/Overlay/FluentOverlay.razor.css new file mode 100644 index 0000000000..61eea638fa --- /dev/null +++ b/src/Core/Components/Overlay/FluentOverlay.razor.css @@ -0,0 +1,8 @@ +.fluent-overlay { + inset: 0px; + display: flex; + pointer-events: auto; + width: 100%; + height: 100%; + overflow: hidden auto; +} \ No newline at end of file diff --git a/src/Core/Microsoft.FluentUI.AspNetCore.Components.csproj b/src/Core/Microsoft.FluentUI.AspNetCore.Components.csproj index 0565cb189c..d96bf7ad2e 100644 --- a/src/Core/Microsoft.FluentUI.AspNetCore.Components.csproj +++ b/src/Core/Microsoft.FluentUI.AspNetCore.Components.csproj @@ -122,7 +122,7 @@ - + diff --git a/src/Core/Utilities/ZIndex.cs b/src/Core/Utilities/ZIndex.cs index ea6eb4830e..6cf6f55800 100644 --- a/src/Core/Utilities/ZIndex.cs +++ b/src/Core/Utilities/ZIndex.cs @@ -34,4 +34,9 @@ public static class ZIndex /// ZIndex for the popup components in the . /// public static int DataGridHeaderPopup { get; set; } = 5; + + /// + /// ZIndex for the component. + /// + public static int Overlay { get; set; } = 9900; } From f0474431fd39e923dee2ebafd98c0b72fa75f4b4 Mon Sep 17 00:00:00 2001 From: MarvinKlein1508 Date: Thu, 27 Nov 2025 10:15:01 +0100 Subject: [PATCH 02/36] Add default demo --- .../Overlay/Examples/OverlayDefault.razor | 31 +++++++++++++++++++ .../Components/Overlay/FluentOverlay.md | 16 ++++++++++ 2 files changed, 47 insertions(+) create mode 100644 examples/Demo/FluentUI.Demo.Client/Documentation/Components/Overlay/Examples/OverlayDefault.razor create mode 100644 examples/Demo/FluentUI.Demo.Client/Documentation/Components/Overlay/FluentOverlay.md diff --git a/examples/Demo/FluentUI.Demo.Client/Documentation/Components/Overlay/Examples/OverlayDefault.razor b/examples/Demo/FluentUI.Demo.Client/Documentation/Components/Overlay/Examples/OverlayDefault.razor new file mode 100644 index 0000000000..43312fe2b3 --- /dev/null +++ b/examples/Demo/FluentUI.Demo.Client/Documentation/Components/Overlay/Examples/OverlayDefault.razor @@ -0,0 +1,31 @@ +@using Microsoft.FluentUI.AspNetCore.Components.Extensions + +()) + OptionValue="@(c => c.ToAttributeValue())" + TOption="JustifyContent" + Position="SelectPosition.Below" +@bind-SelectedOption="@justification" /> + +()) + OptionValue="@(c => c.ToAttributeValue())" + TOption="HorizontalAlignment" + Position="SelectPosition.Below" +@bind-SelectedOption="@alignment" /> +
+
+ + +Show Overlay + + + + + +@code { + bool visible = false; + JustifyContent justification = JustifyContent.Center; + HorizontalAlignment alignment = HorizontalAlignment.Center; +} diff --git a/examples/Demo/FluentUI.Demo.Client/Documentation/Components/Overlay/FluentOverlay.md b/examples/Demo/FluentUI.Demo.Client/Documentation/Components/Overlay/FluentOverlay.md new file mode 100644 index 0000000000..160636b70e --- /dev/null +++ b/examples/Demo/FluentUI.Demo.Client/Documentation/Components/Overlay/FluentOverlay.md @@ -0,0 +1,16 @@ +--- +title: Overlay +route: /Overlay +--- + +# Overlay + +Overlays are used to temporarily overlay screen content to focus a dialog, progress or other information/interaction. + +## Default + +{{ OverlayDefault }} + +## API FluentOverlay + +{{ API Type=FluentOverlay }} From 2ec50b4426fed983515c89482bedfbdc6fc49ac5 Mon Sep 17 00:00:00 2001 From: MarvinKlein1508 Date: Thu, 27 Nov 2025 10:18:27 +0100 Subject: [PATCH 03/36] Use CultureInfo.InvariantCulture --- src/Core/Components/Overlay/FluentOverlay.razor.cs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/Core/Components/Overlay/FluentOverlay.razor.cs b/src/Core/Components/Overlay/FluentOverlay.razor.cs index 9e8f3eefd0..f4d491a15e 100644 --- a/src/Core/Components/Overlay/FluentOverlay.razor.cs +++ b/src/Core/Components/Overlay/FluentOverlay.razor.cs @@ -38,8 +38,7 @@ public FluentOverlay(LibraryConfiguration configuration) : base(configuration) { /// protected string? StyleValue => new StyleBuilder() .AddStyle("cursor", "auto", () => Transparent) - //.AddStyle("background-color", $"rgba({_r}, {_g}, {_b}, {Opacity.ToString()})", () => !Transparent) - ////.AddStyle("opacity", Opacity.ToString()!.Replace(',', '.'), CheckCSSVariableName().IsMatch(BackgroundColor)) + .AddStyle("background-color", string.Create(CultureInfo.InvariantCulture, $"rgba({_r}, {_g}, {_b}, {Opacity})"), () => !Transparent) .AddStyle("cursor", "default", () => !Transparent) .AddStyle("position", FullScreen ? "fixed" : "absolute") .AddStyle("display", "flex") From cfccd257ca2c563bf30f18a40fad2192e1eabd0d Mon Sep 17 00:00:00 2001 From: MarvinKlein1508 Date: Thu, 27 Nov 2025 10:20:25 +0100 Subject: [PATCH 04/36] Use default builders --- src/Core/Components/Overlay/FluentOverlay.razor.cs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/Core/Components/Overlay/FluentOverlay.razor.cs b/src/Core/Components/Overlay/FluentOverlay.razor.cs index f4d491a15e..1112106c5a 100644 --- a/src/Core/Components/Overlay/FluentOverlay.razor.cs +++ b/src/Core/Components/Overlay/FluentOverlay.razor.cs @@ -31,12 +31,13 @@ public FluentOverlay(LibraryConfiguration configuration) : base(configuration) { private IJSObjectReference? _jsModule { get; set; } /// - protected string? ClassValue => new CssBuilder("fluent-overlay") + protected string? ClassValue => DefaultClassBuilder + .AddClass("fluent-overlay") .AddClass("prevent-scroll", PreventScroll) .Build(); /// - protected string? StyleValue => new StyleBuilder() + protected string? StyleValue => DefaultStyleBuilder .AddStyle("cursor", "auto", () => Transparent) .AddStyle("background-color", string.Create(CultureInfo.InvariantCulture, $"rgba({_r}, {_g}, {_b}, {Opacity})"), () => !Transparent) .AddStyle("cursor", "default", () => !Transparent) From 40c84fbd88d970faf4bbef0dae3ebddd2593e9d0 Mon Sep 17 00:00:00 2001 From: MarvinKlein1508 Date: Thu, 27 Nov 2025 10:25:39 +0100 Subject: [PATCH 05/36] Update sample --- .../Overlay/Examples/OverlayDefault.razor | 16 +++++++++++----- .../Components/Overlay/FluentOverlay.razor.cs | 2 +- 2 files changed, 12 insertions(+), 6 deletions(-) diff --git a/examples/Demo/FluentUI.Demo.Client/Documentation/Components/Overlay/Examples/OverlayDefault.razor b/examples/Demo/FluentUI.Demo.Client/Documentation/Components/Overlay/Examples/OverlayDefault.razor index 43312fe2b3..fb07801804 100644 --- a/examples/Demo/FluentUI.Demo.Client/Documentation/Components/Overlay/Examples/OverlayDefault.razor +++ b/examples/Demo/FluentUI.Demo.Client/Documentation/Components/Overlay/Examples/OverlayDefault.razor @@ -3,19 +3,19 @@ ()) OptionValue="@(c => c.ToAttributeValue())" TOption="JustifyContent" - Position="SelectPosition.Below" -@bind-SelectedOption="@justification" /> + Placeholder="Test" + @bind-SelectedOption="@justification" /> ()) OptionValue="@(c => c.ToAttributeValue())" TOption="HorizontalAlignment" - Position="SelectPosition.Below" -@bind-SelectedOption="@alignment" /> + Placeholder="Test" + @bind-SelectedOption="@alignment" />

-Show Overlay +Show Overlay [Parameter] - public bool Visible { get; set; } = false; + public bool Visible { get; set; } /// /// Callback for when overlay visibility changes. From 84d2955e17d9a0b07cbe3c484f4313fe710ef9ee Mon Sep 17 00:00:00 2001 From: MarvinKlein1508 Date: Thu, 27 Nov 2025 10:27:31 +0100 Subject: [PATCH 06/36] Display value --- .../Components/Overlay/Examples/OverlayDefault.razor | 2 ++ 1 file changed, 2 insertions(+) diff --git a/examples/Demo/FluentUI.Demo.Client/Documentation/Components/Overlay/Examples/OverlayDefault.razor b/examples/Demo/FluentUI.Demo.Client/Documentation/Components/Overlay/Examples/OverlayDefault.razor index fb07801804..e48c4645f5 100644 --- a/examples/Demo/FluentUI.Demo.Client/Documentation/Components/Overlay/Examples/OverlayDefault.razor +++ b/examples/Demo/FluentUI.Demo.Client/Documentation/Components/Overlay/Examples/OverlayDefault.razor @@ -5,12 +5,14 @@ TOption="JustifyContent" Placeholder="Test" @bind-SelectedOption="@justification" /> +

Value: @alignment.ToAttributeValue()

()) OptionValue="@(c => c.ToAttributeValue())" TOption="HorizontalAlignment" Placeholder="Test" @bind-SelectedOption="@alignment" /> +

Value: @alignment.ToAttributeValue()



From 9077085acc1717d6df34e5760c1f19cf9eb0dc7f Mon Sep 17 00:00:00 2001 From: MarvinKlein1508 Date: Thu, 27 Nov 2025 10:29:37 +0100 Subject: [PATCH 07/36] Update sample --- .../Components/Overlay/Examples/OverlayDefault.razor | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/examples/Demo/FluentUI.Demo.Client/Documentation/Components/Overlay/Examples/OverlayDefault.razor b/examples/Demo/FluentUI.Demo.Client/Documentation/Components/Overlay/Examples/OverlayDefault.razor index e48c4645f5..e959f84119 100644 --- a/examples/Demo/FluentUI.Demo.Client/Documentation/Components/Overlay/Examples/OverlayDefault.razor +++ b/examples/Demo/FluentUI.Demo.Client/Documentation/Components/Overlay/Examples/OverlayDefault.razor @@ -4,15 +4,14 @@ OptionValue="@(c => c.ToAttributeValue())" TOption="JustifyContent" Placeholder="Test" - @bind-SelectedOption="@justification" /> -

Value: @alignment.ToAttributeValue()

+ @bind-Value="@justification" /> ()) OptionValue="@(c => c.ToAttributeValue())" TOption="HorizontalAlignment" Placeholder="Test" - @bind-SelectedOption="@alignment" /> -

Value: @alignment.ToAttributeValue()

+ @bind-Value="@alignment" /> +

From 80237e69ffb84c72b1f74d6360025988393c6b93 Mon Sep 17 00:00:00 2001 From: MarvinKlein1508 Date: Thu, 27 Nov 2025 10:31:40 +0100 Subject: [PATCH 08/36] Update sample --- .../Components/Overlay/Examples/OverlayDefault.razor | 3 --- 1 file changed, 3 deletions(-) diff --git a/examples/Demo/FluentUI.Demo.Client/Documentation/Components/Overlay/Examples/OverlayDefault.razor b/examples/Demo/FluentUI.Demo.Client/Documentation/Components/Overlay/Examples/OverlayDefault.razor index e959f84119..219c92fd04 100644 --- a/examples/Demo/FluentUI.Demo.Client/Documentation/Components/Overlay/Examples/OverlayDefault.razor +++ b/examples/Demo/FluentUI.Demo.Client/Documentation/Components/Overlay/Examples/OverlayDefault.razor @@ -3,19 +3,16 @@ ()) OptionValue="@(c => c.ToAttributeValue())" TOption="JustifyContent" - Placeholder="Test" @bind-Value="@justification" /> ()) OptionValue="@(c => c.ToAttributeValue())" TOption="HorizontalAlignment" - Placeholder="Test" @bind-Value="@alignment" />

- Show Overlay Date: Thu, 27 Nov 2025 10:32:44 +0100 Subject: [PATCH 09/36] Remove default values for default types --- src/Core/Components/Overlay/FluentOverlay.razor.cs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Core/Components/Overlay/FluentOverlay.razor.cs b/src/Core/Components/Overlay/FluentOverlay.razor.cs index c82e3f9271..d9180a9ef0 100644 --- a/src/Core/Components/Overlay/FluentOverlay.razor.cs +++ b/src/Core/Components/Overlay/FluentOverlay.razor.cs @@ -103,21 +103,21 @@ public FluentOverlay(LibraryConfiguration configuration) : base(configuration) { /// Gets or sets a value indicating whether the overlay is shown full screen or bound to the containing element. ///
[Parameter] - public bool FullScreen { get; set; } = false; + public bool FullScreen { get; set; } /// /// Gets or sets a value indicating whether the overlay is interactive, except for the element with the specified . /// In other words, the elements below the overlay remain usable (mouse-over, click) and the overlay will closed when clicked. /// [Parameter] - public bool Interactive { get; set; } = false; + public bool Interactive { get; set; } /// /// Gets or sets the HTML identifier of the element that is not interactive when the overlay is shown. /// This property is ignored if is false. /// [Parameter] - public string? InteractiveExceptId { get; set; } = null; + public string? InteractiveExceptId { get; set; } /// /// Gets of sets a value indicating if the overlay can be dismissed by clicking on it. @@ -136,7 +136,7 @@ public FluentOverlay(LibraryConfiguration configuration) : base(configuration) { /// [Parameter] - public bool PreventScroll { get; set; } = false; + public bool PreventScroll { get; set; } /// [Parameter] From 5102804ef9004af502767060513762203953b7a3 Mon Sep 17 00:00:00 2001 From: MarvinKlein1508 Date: Thu, 27 Nov 2025 10:38:23 +0100 Subject: [PATCH 10/36] Added timed demo --- .../Overlay/Examples/OverlayDefault.razor | 8 ++--- .../Overlay/Examples/OverlayTimed.razor | 34 +++++++++++++++++++ .../Components/Overlay/FluentOverlay.md | 6 ++++ 3 files changed, 43 insertions(+), 5 deletions(-) create mode 100644 examples/Demo/FluentUI.Demo.Client/Documentation/Components/Overlay/Examples/OverlayTimed.razor diff --git a/examples/Demo/FluentUI.Demo.Client/Documentation/Components/Overlay/Examples/OverlayDefault.razor b/examples/Demo/FluentUI.Demo.Client/Documentation/Components/Overlay/Examples/OverlayDefault.razor index 219c92fd04..368d929860 100644 --- a/examples/Demo/FluentUI.Demo.Client/Documentation/Components/Overlay/Examples/OverlayDefault.razor +++ b/examples/Demo/FluentUI.Demo.Client/Documentation/Components/Overlay/Examples/OverlayDefault.razor @@ -2,12 +2,10 @@ ()) OptionValue="@(c => c.ToAttributeValue())" - TOption="JustifyContent" @bind-Value="@justification" /> ()) OptionValue="@(c => c.ToAttributeValue())" - TOption="HorizontalAlignment" @bind-Value="@alignment" />
@@ -23,9 +21,9 @@ @code { - bool visible = false; - JustifyContent justification = JustifyContent.Center; - HorizontalAlignment alignment = HorizontalAlignment.Center; + private bool visible; + private JustifyContent justification = JustifyContent.Center; + private HorizontalAlignment alignment = HorizontalAlignment.Center; private Task ShowOverlay() { diff --git a/examples/Demo/FluentUI.Demo.Client/Documentation/Components/Overlay/Examples/OverlayTimed.razor b/examples/Demo/FluentUI.Demo.Client/Documentation/Components/Overlay/Examples/OverlayTimed.razor new file mode 100644 index 0000000000..1a92f9cb90 --- /dev/null +++ b/examples/Demo/FluentUI.Demo.Client/Documentation/Components/Overlay/Examples/OverlayTimed.razor @@ -0,0 +1,34 @@ +@using Microsoft.FluentUI.AspNetCore.Components.Extensions + +()) + OptionValue="@(c => c.ToAttributeValue())" + @bind-Value="@justification" /> + +()) + OptionValue="@(c => c.ToAttributeValue())" + @bind-Value="@alignment" /> +
+
+ +Show Overlay + + + + + +@code { + private bool visible; + private JustifyContent justification = JustifyContent.Center; + private HorizontalAlignment alignment = HorizontalAlignment.Center; + + protected async Task HandleOnOpen() + { + visible = true; + //DemoLogger.WriteLine("Overlay opened"); + await Task.Delay(3000); + visible = false; + } +} diff --git a/examples/Demo/FluentUI.Demo.Client/Documentation/Components/Overlay/FluentOverlay.md b/examples/Demo/FluentUI.Demo.Client/Documentation/Components/Overlay/FluentOverlay.md index 160636b70e..70099515ae 100644 --- a/examples/Demo/FluentUI.Demo.Client/Documentation/Components/Overlay/FluentOverlay.md +++ b/examples/Demo/FluentUI.Demo.Client/Documentation/Components/Overlay/FluentOverlay.md @@ -11,6 +11,12 @@ Overlays are used to temporarily overlay screen content to focus a dialog, progr {{ OverlayDefault }} +## Timed + +A timed overlay that hides after being shown for 3 seconds + +{{ OverlayTimed }} + ## API FluentOverlay {{ API Type=FluentOverlay }} From 4c7adfb6e2a43b14f0c66fb99bdf13de49bb618c Mon Sep 17 00:00:00 2001 From: MarvinKlein1508 Date: Thu, 27 Nov 2025 10:38:48 +0100 Subject: [PATCH 11/36] Update default demo --- .../Components/Overlay/Examples/OverlayDefault.razor | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/examples/Demo/FluentUI.Demo.Client/Documentation/Components/Overlay/Examples/OverlayDefault.razor b/examples/Demo/FluentUI.Demo.Client/Documentation/Components/Overlay/Examples/OverlayDefault.razor index 368d929860..9f06101d06 100644 --- a/examples/Demo/FluentUI.Demo.Client/Documentation/Components/Overlay/Examples/OverlayDefault.razor +++ b/examples/Demo/FluentUI.Demo.Client/Documentation/Components/Overlay/Examples/OverlayDefault.razor @@ -13,10 +13,10 @@ Show Overlay - + Alignment="alignment" + Justification="justification"> From 1948396aca456c0e45e04299f462540626e06bf6 Mon Sep 17 00:00:00 2001 From: MarvinKlein1508 Date: Thu, 27 Nov 2025 10:40:22 +0100 Subject: [PATCH 12/36] Added transparent demo --- .../Overlay/Examples/OverlayTransparent.razor | 15 +++++++++++++++ .../Components/Overlay/FluentOverlay.md | 6 ++++++ 2 files changed, 21 insertions(+) create mode 100644 examples/Demo/FluentUI.Demo.Client/Documentation/Components/Overlay/Examples/OverlayTransparent.razor diff --git a/examples/Demo/FluentUI.Demo.Client/Documentation/Components/Overlay/Examples/OverlayTransparent.razor b/examples/Demo/FluentUI.Demo.Client/Documentation/Components/Overlay/Examples/OverlayTransparent.razor new file mode 100644 index 0000000000..f0510e176c --- /dev/null +++ b/examples/Demo/FluentUI.Demo.Client/Documentation/Components/Overlay/Examples/OverlayTransparent.razor @@ -0,0 +1,15 @@ + +Show Overlay + + + + + +@code { + private bool visible; + + protected void HandleOnClose() + { + //DemoLogger.WriteLine("Transparent overlay closed"); + } +} diff --git a/examples/Demo/FluentUI.Demo.Client/Documentation/Components/Overlay/FluentOverlay.md b/examples/Demo/FluentUI.Demo.Client/Documentation/Components/Overlay/FluentOverlay.md index 70099515ae..f64c333a6f 100644 --- a/examples/Demo/FluentUI.Demo.Client/Documentation/Components/Overlay/FluentOverlay.md +++ b/examples/Demo/FluentUI.Demo.Client/Documentation/Components/Overlay/FluentOverlay.md @@ -17,6 +17,12 @@ A timed overlay that hides after being shown for 3 seconds {{ OverlayTimed }} +## Transparent overlay + +Overlay with a transparent background + +{{ OverlayTransparent }} + ## API FluentOverlay {{ API Type=FluentOverlay }} From ccfbfbadd359c9d5b793bff6c0ea2b36b71c75c1 Mon Sep 17 00:00:00 2001 From: MarvinKlein1508 Date: Thu, 27 Nov 2025 10:41:48 +0100 Subject: [PATCH 13/36] Added background color demo --- .../Examples/OverlayBackgroundColor.razor | 18 ++++++++++++++++++ .../Components/Overlay/FluentOverlay.md | 6 ++++++ 2 files changed, 24 insertions(+) create mode 100644 examples/Demo/FluentUI.Demo.Client/Documentation/Components/Overlay/Examples/OverlayBackgroundColor.razor diff --git a/examples/Demo/FluentUI.Demo.Client/Documentation/Components/Overlay/Examples/OverlayBackgroundColor.razor b/examples/Demo/FluentUI.Demo.Client/Documentation/Components/Overlay/Examples/OverlayBackgroundColor.razor new file mode 100644 index 0000000000..56dd4ceaf5 --- /dev/null +++ b/examples/Demo/FluentUI.Demo.Client/Documentation/Components/Overlay/Examples/OverlayBackgroundColor.razor @@ -0,0 +1,18 @@ + +Show Overlay + + + + + +@code { + private bool visible; + + protected void HandleOnClose() + { + //DemoLogger.WriteLine("Custom background color overlay closed"); + } +} diff --git a/examples/Demo/FluentUI.Demo.Client/Documentation/Components/Overlay/FluentOverlay.md b/examples/Demo/FluentUI.Demo.Client/Documentation/Components/Overlay/FluentOverlay.md index f64c333a6f..04f78a41b1 100644 --- a/examples/Demo/FluentUI.Demo.Client/Documentation/Components/Overlay/FluentOverlay.md +++ b/examples/Demo/FluentUI.Demo.Client/Documentation/Components/Overlay/FluentOverlay.md @@ -23,6 +23,12 @@ Overlay with a transparent background {{ OverlayTransparent }} +## Background color + +Overlay with a custom background color + +{{ OverlayBackgroundColor }} + ## API FluentOverlay {{ API Type=FluentOverlay }} From cc44c1701d60276caaba22af122820ef9699371a Mon Sep 17 00:00:00 2001 From: MarvinKlein1508 Date: Thu, 27 Nov 2025 10:43:18 +0100 Subject: [PATCH 14/36] Add fullscreen demo --- .../Overlay/Examples/OverlayFullScreen.razor | 20 +++++++++++++++++++ .../Components/Overlay/FluentOverlay.md | 6 ++++++ 2 files changed, 26 insertions(+) create mode 100644 examples/Demo/FluentUI.Demo.Client/Documentation/Components/Overlay/Examples/OverlayFullScreen.razor diff --git a/examples/Demo/FluentUI.Demo.Client/Documentation/Components/Overlay/Examples/OverlayFullScreen.razor b/examples/Demo/FluentUI.Demo.Client/Documentation/Components/Overlay/Examples/OverlayFullScreen.razor new file mode 100644 index 0000000000..fbd2826400 --- /dev/null +++ b/examples/Demo/FluentUI.Demo.Client/Documentation/Components/Overlay/Examples/OverlayFullScreen.razor @@ -0,0 +1,20 @@ + +Show Overlay + + + + + +@code { + private bool visible; + + protected void HandleOnClose() + { + //DemoLogger.WriteLine("Full screen overlay closed"); + } +} diff --git a/examples/Demo/FluentUI.Demo.Client/Documentation/Components/Overlay/FluentOverlay.md b/examples/Demo/FluentUI.Demo.Client/Documentation/Components/Overlay/FluentOverlay.md index 04f78a41b1..c7bbafcb0e 100644 --- a/examples/Demo/FluentUI.Demo.Client/Documentation/Components/Overlay/FluentOverlay.md +++ b/examples/Demo/FluentUI.Demo.Client/Documentation/Components/Overlay/FluentOverlay.md @@ -29,6 +29,12 @@ Overlay with a custom background color {{ OverlayBackgroundColor }} +## Full screen + +Overlay which takes up the whole screen. + +{{ OverlayFullScreen }} + ## API FluentOverlay {{ API Type=FluentOverlay }} From eaafd00d6aba5d0c2236ce1f5caf54b42f02317d Mon Sep 17 00:00:00 2001 From: MarvinKlein1508 Date: Thu, 27 Nov 2025 10:47:59 +0100 Subject: [PATCH 15/36] Add Interactive demo --- .../Overlay/Examples/OverlayInteractive.razor | 67 +++++++++++++++++++ .../Components/Overlay/FluentOverlay.md | 6 ++ 2 files changed, 73 insertions(+) create mode 100644 examples/Demo/FluentUI.Demo.Client/Documentation/Components/Overlay/Examples/OverlayInteractive.razor diff --git a/examples/Demo/FluentUI.Demo.Client/Documentation/Components/Overlay/Examples/OverlayInteractive.razor b/examples/Demo/FluentUI.Demo.Client/Documentation/Components/Overlay/Examples/OverlayInteractive.razor new file mode 100644 index 0000000000..e3fed743b4 --- /dev/null +++ b/examples/Demo/FluentUI.Demo.Client/Documentation/Components/Overlay/Examples/OverlayInteractive.razor @@ -0,0 +1,67 @@ + + + + + + + + + Show Overlay + + + + Increment + Counter: @counter + + + + @if (interactive) + { +
+

Non-interactive zone

+ +
+ } + else + { + + } +
+ + + +@code { + bool visible = false; + bool interactive = true; + bool interactiveExceptId = true; + bool fullScreen = true; + int counter = 0; + + protected void HandleOnClose() + { + //DemoLogger.WriteLine("Overlay closed"); + } +} diff --git a/examples/Demo/FluentUI.Demo.Client/Documentation/Components/Overlay/FluentOverlay.md b/examples/Demo/FluentUI.Demo.Client/Documentation/Components/Overlay/FluentOverlay.md index c7bbafcb0e..b4b4bd6450 100644 --- a/examples/Demo/FluentUI.Demo.Client/Documentation/Components/Overlay/FluentOverlay.md +++ b/examples/Demo/FluentUI.Demo.Client/Documentation/Components/Overlay/FluentOverlay.md @@ -35,6 +35,12 @@ Overlay which takes up the whole screen. {{ OverlayFullScreen }} +## Interactive +By using the `Interactive` and `InteractiveExceptId` properties, only the targeted element will not close the FluentOverlay panel. The user can click anywhere else to close the FluentOverlay. +In this example, the FluentOverlay will only close when the user clicks outside the white zone and the user can increment the counter before to close the Overlay. + +{{ OverlayInteractive }} + ## API FluentOverlay {{ API Type=FluentOverlay }} From ec8331984eedad068c89dc76bba141dabf7722ee Mon Sep 17 00:00:00 2001 From: MarvinKlein1508 Date: Thu, 27 Nov 2025 15:38:59 +0100 Subject: [PATCH 16/36] Work on FluentOverlay interactive --- .../Components/Overlay/FluentOverlay.razor.cs | 80 +++++-------------- .../Components/Overlay/FluentOverlay.razor.ts | 57 +++++++++++++ ...soft.FluentUI.AspNetCore.Components.csproj | 4 + 3 files changed, 83 insertions(+), 58 deletions(-) create mode 100644 src/Core/Components/Overlay/FluentOverlay.razor.ts diff --git a/src/Core/Components/Overlay/FluentOverlay.razor.cs b/src/Core/Components/Overlay/FluentOverlay.razor.cs index d9180a9ef0..e0b4277ea6 100644 --- a/src/Core/Components/Overlay/FluentOverlay.razor.cs +++ b/src/Core/Components/Overlay/FluentOverlay.razor.cs @@ -15,7 +15,8 @@ namespace Microsoft.FluentUI.AspNetCore.Components; /// public partial class FluentOverlay : FluentComponentBase, IAsyncDisposable { - private readonly string _defaultId = Identifier.NewId(); + private const string JAVASCRIPT_FILE = FluentJSModule.JAVASCRIPT_ROOT + "Menu/FluentOverlay.razor.js"; + private string? _color; private int _r, _g, _b; @@ -25,10 +26,10 @@ public partial class FluentOverlay : FluentComponentBase, IAsyncDisposable private DotNetObjectReference? _dotNetHelper; /// - public FluentOverlay(LibraryConfiguration configuration) : base(configuration) { } - - /// - private IJSObjectReference? _jsModule { get; set; } + public FluentOverlay(LibraryConfiguration configuration) : base(configuration) + { + Id = Identifier.NewId(); + } /// protected string? ClassValue => DefaultClassBuilder @@ -143,27 +144,25 @@ public FluentOverlay(LibraryConfiguration configuration) : base(configuration) { public RenderFragment? ChildContent { get; set; } /// - protected override async Task OnParametersSetAsync() + protected override async Task OnAfterRenderAsync(bool firstRender) { - if (Interactive) + if (firstRender) { - if (string.IsNullOrEmpty(Id)) - { - Id = _defaultId; - } + // Import the JavaScript module + _dotNetHelper ??= DotNetObjectReference.Create(this); + var jsModule = await JSModule.ImportJavaScriptModuleAsync(JAVASCRIPT_FILE); - if (Visible) + if (Interactive) { - // Add a document.addEventListener when Visible is true - await InvokeOverlayInitializeAsync(); - } - else - { - // Remove a document.addEventListener when Visible is false - await InvokeOverlayDisposeAsync(); + var containerId = FullScreen ? null : Id; + await jsModule.InvokeVoidAsync("Microsoft.FluentUI.Blazor.Overlay.Initialize", _dotNetHelper, containerId, InteractiveExceptId); } } + } + /// + protected override async Task OnParametersSetAsync() + { if (!Transparent && Opacity is null) { Opacity = 0.4; @@ -207,7 +206,7 @@ public async Task OnCloseInteractiveAsync(MouseEventArgs e) } // Remove the document.removeEventListener - await InvokeOverlayDisposeAsync(); + //await InvokeOverlayDisposeAsync(); // Close the overlay await OnCloseInternalHandlerAsync(e); @@ -240,47 +239,12 @@ private async Task OnCloseInternalHandlerAsync(MouseEventArgs e) } } - /// - /// Disposes the overlay. - /// - /// - public override async ValueTask DisposeAsync() - { - await base.DisposeAsync(); - - try - { - await InvokeOverlayDisposeAsync(); - - if (_jsModule != null) - { - await _jsModule.DisposeAsync(); - } - } - catch (Exception ex) when (ex is JSDisconnectedException || - ex is OperationCanceledException) - { - // The JSRuntime side may routinely be gone already if the reason we're disposing is that - // the client disconnected. This is not an error. - } - } - - /// - private async Task InvokeOverlayInitializeAsync() - { - _dotNetHelper ??= DotNetObjectReference.Create(this); - //_jsModule ??= await JSRuntime.InvokeAsync("import", JAVASCRIPT_FILE.FormatCollocatedUrl(LibraryConfiguration)); - - //var containerId = FullScreen ? null : Id; - //await _jsModule.InvokeVoidAsync("overlayInitialize", _dotNetHelper, containerId, InteractiveExceptId); - } - /// - private async Task InvokeOverlayDisposeAsync() + protected override async ValueTask DisposeAsync(IJSObjectReference jsModule) { - if (_jsModule != null && Interactive) + if (Interactive) { - await _jsModule.InvokeVoidAsync("overlayDispose", InteractiveExceptId); + await jsModule.InvokeVoidAsync("Microsoft.FluentUI.Blazor.Overlay.overlayDispose", InteractiveExceptId); } } diff --git a/src/Core/Components/Overlay/FluentOverlay.razor.ts b/src/Core/Components/Overlay/FluentOverlay.razor.ts new file mode 100644 index 0000000000..96fe92bcc6 --- /dev/null +++ b/src/Core/Components/Overlay/FluentOverlay.razor.ts @@ -0,0 +1,57 @@ +export namespace Microsoft.FluentUI.Blazor.Overlay { + export function Initialize(dotNetHelper: any, containerId: string, id: string) { + const _document = document as any; + + if (!_document.fluentOverlayData) { + _document.fluentOverlayData = {}; + } + + if (_document.fluentOverlayData[id]) { + return; + } + + // Store the data + _document.fluentOverlayData[id] = { + + // Click event handler + clickHandler: async function (event: MouseEvent) { + const isInsideContainer = isClickInsideContainer(event, document.getElementById(containerId)); + const isInsideExcludedElement = !!document.getElementById(id) && isClickInsideContainer(event, document.getElementById(id)); + + if (isInsideContainer && !isInsideExcludedElement) { + dotNetHelper.invokeMethodAsync('OnCloseInteractiveAsync', event); + } + } + }; + + // Let the user click on the container (containerId or the entire document) + document.addEventListener('click', _document.fluentOverlayData[id].clickHandler); + } + export function overlayDispose(id: string) { + const _document = document as any; + if (_document.fluentOverlayData[id]) { + + // Remove the event listener + document.removeEventListener('click', _document.fluentOverlayData[id].clickHandler); + + // Remove the data + _document.fluentOverlayData[id] = null; + delete _document.fluentOverlayData[id]; + } + } + function isClickInsideContainer(event: MouseEvent, container: any) { + if (!!container) { + const rect = container.getBoundingClientRect(); + + return ( + event.clientX >= rect.left && + event.clientX <= rect.right && + event.clientY >= rect.top && + event.clientY <= rect.bottom + ); + } + + // Default is true + return true; + } +} diff --git a/src/Core/Microsoft.FluentUI.AspNetCore.Components.csproj b/src/Core/Microsoft.FluentUI.AspNetCore.Components.csproj index d96bf7ad2e..c6485c3ac6 100644 --- a/src/Core/Microsoft.FluentUI.AspNetCore.Components.csproj +++ b/src/Core/Microsoft.FluentUI.AspNetCore.Components.csproj @@ -57,6 +57,10 @@ + + + + From d0362f398b3815bbeda2d6029bff867a8247c1f3 Mon Sep 17 00:00:00 2001 From: MarvinKlein1508 Date: Thu, 27 Nov 2025 15:43:22 +0100 Subject: [PATCH 17/36] Fix path --- src/Core/Components/Overlay/FluentOverlay.razor.cs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/Core/Components/Overlay/FluentOverlay.razor.cs b/src/Core/Components/Overlay/FluentOverlay.razor.cs index e0b4277ea6..72581cc7b4 100644 --- a/src/Core/Components/Overlay/FluentOverlay.razor.cs +++ b/src/Core/Components/Overlay/FluentOverlay.razor.cs @@ -15,12 +15,11 @@ namespace Microsoft.FluentUI.AspNetCore.Components; /// public partial class FluentOverlay : FluentComponentBase, IAsyncDisposable { - private const string JAVASCRIPT_FILE = FluentJSModule.JAVASCRIPT_ROOT + "Menu/FluentOverlay.razor.js"; + private const string JAVASCRIPT_FILE = FluentJSModule.JAVASCRIPT_ROOT + "Overlay/FluentOverlay.razor.js"; private string? _color; private int _r, _g, _b; - //private const string JAVASCRIPT_FILE = "./_content/Microsoft.FluentUI.AspNetCore.Components/Components/Overlay/FluentOverlay.razor.js"; private const string DEFAULT_NEUTRAL_COLOR = "#808080"; private DotNetObjectReference? _dotNetHelper; From 4eed8bff14f9d556e5155cf4f24a60485366533d Mon Sep 17 00:00:00 2001 From: MarvinKlein1508 Date: Thu, 27 Nov 2025 15:47:56 +0100 Subject: [PATCH 18/36] Work on overlay --- .../Components/Overlay/FluentOverlay.razor.cs | 42 +++++++++++++------ 1 file changed, 29 insertions(+), 13 deletions(-) diff --git a/src/Core/Components/Overlay/FluentOverlay.razor.cs b/src/Core/Components/Overlay/FluentOverlay.razor.cs index 72581cc7b4..e71d6f710a 100644 --- a/src/Core/Components/Overlay/FluentOverlay.razor.cs +++ b/src/Core/Components/Overlay/FluentOverlay.razor.cs @@ -143,25 +143,22 @@ public FluentOverlay(LibraryConfiguration configuration) : base(configuration) public RenderFragment? ChildContent { get; set; } /// - protected override async Task OnAfterRenderAsync(bool firstRender) + protected override async Task OnParametersSetAsync() { - if (firstRender) + if (Interactive) { - // Import the JavaScript module - _dotNetHelper ??= DotNetObjectReference.Create(this); - var jsModule = await JSModule.ImportJavaScriptModuleAsync(JAVASCRIPT_FILE); - - if (Interactive) + if (Visible) + { + // Add a document.addEventListener when Visible is true + await InvokeOverlayInitializeAsync(); + } + else { - var containerId = FullScreen ? null : Id; - await jsModule.InvokeVoidAsync("Microsoft.FluentUI.Blazor.Overlay.Initialize", _dotNetHelper, containerId, InteractiveExceptId); + // Remove a document.addEventListener when Visible is false + await InvokeOverlayDisposeAsync(); } } - } - /// - protected override async Task OnParametersSetAsync() - { if (!Transparent && Opacity is null) { Opacity = 0.4; @@ -247,6 +244,25 @@ protected override async ValueTask DisposeAsync(IJSObjectReference jsModule) } } + /// + private async Task InvokeOverlayInitializeAsync() + { + _dotNetHelper ??= DotNetObjectReference.Create(this); + var jsModule = await JSModule.ImportJavaScriptModuleAsync(JAVASCRIPT_FILE); + + var containerId = FullScreen ? null : Id; + await jsModule.InvokeVoidAsync("Microsoft.FluentUI.Blazor.Overlay.Initialize", _dotNetHelper, containerId, InteractiveExceptId); + } + + /// + private async Task InvokeOverlayDisposeAsync() + { + if (JSModule.ObjectReference != null && Interactive) + { + await JSModule.ObjectReference.InvokeVoidAsync("Microsoft.FluentUI.Blazor.Overlay.overlayDispose", InteractiveExceptId); + } + } + [GeneratedRegex("^(?:#(?:[a-fA-F0-9]{6}|[a-fA-F0-9]{3}))", RegexOptions.None, matchTimeoutMilliseconds: 1000)] //Add timeout to prevent ReDoS private static partial Regex CheckRGBString(); } From 493d9a5712dd80bbc4062ed297ece4960a6d6b80 Mon Sep 17 00:00:00 2001 From: MarvinKlein1508 Date: Thu, 27 Nov 2025 15:49:25 +0100 Subject: [PATCH 19/36] Comment in --- src/Core/Components/Overlay/FluentOverlay.razor.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Core/Components/Overlay/FluentOverlay.razor.cs b/src/Core/Components/Overlay/FluentOverlay.razor.cs index e71d6f710a..a10969aa7a 100644 --- a/src/Core/Components/Overlay/FluentOverlay.razor.cs +++ b/src/Core/Components/Overlay/FluentOverlay.razor.cs @@ -202,7 +202,7 @@ public async Task OnCloseInteractiveAsync(MouseEventArgs e) } // Remove the document.removeEventListener - //await InvokeOverlayDisposeAsync(); + await InvokeOverlayDisposeAsync(); // Close the overlay await OnCloseInternalHandlerAsync(e); From 32f71e0285116fadbf61d7ce2cf1ff9ff32445fa Mon Sep 17 00:00:00 2001 From: MarvinKlein1508 Date: Thu, 27 Nov 2025 15:57:41 +0100 Subject: [PATCH 20/36] Work on interactive mode --- src/Core/Components/Overlay/FluentOverlay.razor.cs | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/Core/Components/Overlay/FluentOverlay.razor.cs b/src/Core/Components/Overlay/FluentOverlay.razor.cs index a10969aa7a..ddf4f158a3 100644 --- a/src/Core/Components/Overlay/FluentOverlay.razor.cs +++ b/src/Core/Components/Overlay/FluentOverlay.razor.cs @@ -155,7 +155,7 @@ protected override async Task OnParametersSetAsync() else { // Remove a document.addEventListener when Visible is false - await InvokeOverlayDisposeAsync(); + //await InvokeOverlayDisposeAsync(); } } @@ -248,10 +248,9 @@ protected override async ValueTask DisposeAsync(IJSObjectReference jsModule) private async Task InvokeOverlayInitializeAsync() { _dotNetHelper ??= DotNetObjectReference.Create(this); - var jsModule = await JSModule.ImportJavaScriptModuleAsync(JAVASCRIPT_FILE); - + await JSModule.ImportJavaScriptModuleAsync(JAVASCRIPT_FILE); var containerId = FullScreen ? null : Id; - await jsModule.InvokeVoidAsync("Microsoft.FluentUI.Blazor.Overlay.Initialize", _dotNetHelper, containerId, InteractiveExceptId); + await JSModule.ObjectReference.InvokeVoidAsync("Microsoft.FluentUI.Blazor.Overlay.Initialize", _dotNetHelper, containerId, InteractiveExceptId); } /// From d1c5129fce2d7ab5cfa25aa7d1e47a8fc6253724 Mon Sep 17 00:00:00 2001 From: MarvinKlein1508 Date: Thu, 27 Nov 2025 16:06:32 +0100 Subject: [PATCH 21/36] Fix interactive mode --- .../Components/Overlay/FluentOverlay.razor.cs | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/src/Core/Components/Overlay/FluentOverlay.razor.cs b/src/Core/Components/Overlay/FluentOverlay.razor.cs index ddf4f158a3..07af1492f7 100644 --- a/src/Core/Components/Overlay/FluentOverlay.razor.cs +++ b/src/Core/Components/Overlay/FluentOverlay.razor.cs @@ -142,10 +142,19 @@ public FluentOverlay(LibraryConfiguration configuration) : base(configuration) [Parameter] public RenderFragment? ChildContent { get; set; } + /// + protected override async Task OnAfterRenderAsync(bool firstRender) + { + if (firstRender) + { + _dotNetHelper ??= DotNetObjectReference.Create(this); + await JSModule.ImportJavaScriptModuleAsync(JAVASCRIPT_FILE); + } + } /// protected override async Task OnParametersSetAsync() { - if (Interactive) + if (Interactive && JSModule.Imported) { if (Visible) { @@ -155,7 +164,7 @@ protected override async Task OnParametersSetAsync() else { // Remove a document.addEventListener when Visible is false - //await InvokeOverlayDisposeAsync(); + await InvokeOverlayDisposeAsync(); } } @@ -247,8 +256,6 @@ protected override async ValueTask DisposeAsync(IJSObjectReference jsModule) /// private async Task InvokeOverlayInitializeAsync() { - _dotNetHelper ??= DotNetObjectReference.Create(this); - await JSModule.ImportJavaScriptModuleAsync(JAVASCRIPT_FILE); var containerId = FullScreen ? null : Id; await JSModule.ObjectReference.InvokeVoidAsync("Microsoft.FluentUI.Blazor.Overlay.Initialize", _dotNetHelper, containerId, InteractiveExceptId); } From bb188958c7458514d1fcd73a4ed84d4592013821 Mon Sep 17 00:00:00 2001 From: MarvinKlein1508 Date: Thu, 27 Nov 2025 16:07:48 +0100 Subject: [PATCH 22/36] Use existing method for disposing --- src/Core/Components/Overlay/FluentOverlay.razor.cs | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/Core/Components/Overlay/FluentOverlay.razor.cs b/src/Core/Components/Overlay/FluentOverlay.razor.cs index 07af1492f7..d20fa9309c 100644 --- a/src/Core/Components/Overlay/FluentOverlay.razor.cs +++ b/src/Core/Components/Overlay/FluentOverlay.razor.cs @@ -247,10 +247,7 @@ private async Task OnCloseInternalHandlerAsync(MouseEventArgs e) /// protected override async ValueTask DisposeAsync(IJSObjectReference jsModule) { - if (Interactive) - { - await jsModule.InvokeVoidAsync("Microsoft.FluentUI.Blazor.Overlay.overlayDispose", InteractiveExceptId); - } + await InvokeOverlayDisposeAsync(); } /// From 03c061ec8f227173d864a5818e6b43c29f2ae328 Mon Sep 17 00:00:00 2001 From: MarvinKlein1508 Date: Thu, 27 Nov 2025 16:10:15 +0100 Subject: [PATCH 23/36] Code cleanup --- src/Core/Components/Overlay/FluentOverlay.razor.cs | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/src/Core/Components/Overlay/FluentOverlay.razor.cs b/src/Core/Components/Overlay/FluentOverlay.razor.cs index d20fa9309c..726aeee671 100644 --- a/src/Core/Components/Overlay/FluentOverlay.razor.cs +++ b/src/Core/Components/Overlay/FluentOverlay.razor.cs @@ -13,15 +13,13 @@ namespace Microsoft.FluentUI.AspNetCore.Components; /// -public partial class FluentOverlay : FluentComponentBase, IAsyncDisposable +public partial class FluentOverlay : FluentComponentBase { private const string JAVASCRIPT_FILE = FluentJSModule.JAVASCRIPT_ROOT + "Overlay/FluentOverlay.razor.js"; + private const string DEFAULT_NEUTRAL_COLOR = "#808080"; private string? _color; private int _r, _g, _b; - - private const string DEFAULT_NEUTRAL_COLOR = "#808080"; - private DotNetObjectReference? _dotNetHelper; /// @@ -178,7 +176,7 @@ protected override async Task OnParametersSetAsync() Transparent = false; } - BackgroundColor ??= DEFAULT_NEUTRAL_COLOR;//GlobalState.NeutralColor ?? DEFAULT_NEUTRAL_COLOR; + BackgroundColor ??= DEFAULT_NEUTRAL_COLOR; if (!CheckRGBString().IsMatch(BackgroundColor)) { From 419a329715c79463d493047989123dee9cb5beed Mon Sep 17 00:00:00 2001 From: MarvinKlein1508 Date: Thu, 27 Nov 2025 16:12:43 +0100 Subject: [PATCH 24/36] Remove obsolete component --- .../Components/Overlay/Examples/OverlayBackgroundColor.razor | 2 +- .../Components/Overlay/Examples/OverlayDefault.razor | 2 +- .../Components/Overlay/Examples/OverlayFullScreen.razor | 2 +- .../Components/Overlay/Examples/OverlayInteractive.razor | 2 +- .../Components/Overlay/Examples/OverlayTimed.razor | 2 +- .../Components/Overlay/Examples/OverlayTransparent.razor | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) diff --git a/examples/Demo/FluentUI.Demo.Client/Documentation/Components/Overlay/Examples/OverlayBackgroundColor.razor b/examples/Demo/FluentUI.Demo.Client/Documentation/Components/Overlay/Examples/OverlayBackgroundColor.razor index 56dd4ceaf5..4ee1d44164 100644 --- a/examples/Demo/FluentUI.Demo.Client/Documentation/Components/Overlay/Examples/OverlayBackgroundColor.razor +++ b/examples/Demo/FluentUI.Demo.Client/Documentation/Components/Overlay/Examples/OverlayBackgroundColor.razor @@ -5,7 +5,7 @@ Opacity="0.6" BackgroundColor="#e8f48c" OnClose="HandleOnClose"> - + @code { diff --git a/examples/Demo/FluentUI.Demo.Client/Documentation/Components/Overlay/Examples/OverlayDefault.razor b/examples/Demo/FluentUI.Demo.Client/Documentation/Components/Overlay/Examples/OverlayDefault.razor index 9f06101d06..b777d5d091 100644 --- a/examples/Demo/FluentUI.Demo.Client/Documentation/Components/Overlay/Examples/OverlayDefault.razor +++ b/examples/Demo/FluentUI.Demo.Client/Documentation/Components/Overlay/Examples/OverlayDefault.razor @@ -17,7 +17,7 @@ Transparent="false" Alignment="alignment" Justification="justification"> - + @code { diff --git a/examples/Demo/FluentUI.Demo.Client/Documentation/Components/Overlay/Examples/OverlayFullScreen.razor b/examples/Demo/FluentUI.Demo.Client/Documentation/Components/Overlay/Examples/OverlayFullScreen.razor index fbd2826400..14bbf8c571 100644 --- a/examples/Demo/FluentUI.Demo.Client/Documentation/Components/Overlay/Examples/OverlayFullScreen.razor +++ b/examples/Demo/FluentUI.Demo.Client/Documentation/Components/Overlay/Examples/OverlayFullScreen.razor @@ -7,7 +7,7 @@ FullScreen="true" OnClose="HandleOnClose" PreventScroll=true> - + @code { diff --git a/examples/Demo/FluentUI.Demo.Client/Documentation/Components/Overlay/Examples/OverlayInteractive.razor b/examples/Demo/FluentUI.Demo.Client/Documentation/Components/Overlay/Examples/OverlayInteractive.razor index e3fed743b4..7fe42104e6 100644 --- a/examples/Demo/FluentUI.Demo.Client/Documentation/Components/Overlay/Examples/OverlayInteractive.razor +++ b/examples/Demo/FluentUI.Demo.Client/Documentation/Components/Overlay/Examples/OverlayInteractive.razor @@ -28,7 +28,7 @@ {

Non-interactive zone

- +
} else diff --git a/examples/Demo/FluentUI.Demo.Client/Documentation/Components/Overlay/Examples/OverlayTimed.razor b/examples/Demo/FluentUI.Demo.Client/Documentation/Components/Overlay/Examples/OverlayTimed.razor index 1a92f9cb90..640870da2e 100644 --- a/examples/Demo/FluentUI.Demo.Client/Documentation/Components/Overlay/Examples/OverlayTimed.razor +++ b/examples/Demo/FluentUI.Demo.Client/Documentation/Components/Overlay/Examples/OverlayTimed.razor @@ -16,7 +16,7 @@ Opacity="0.4" Alignment="alignment" Justification="justification"> - + @code { diff --git a/examples/Demo/FluentUI.Demo.Client/Documentation/Components/Overlay/Examples/OverlayTransparent.razor b/examples/Demo/FluentUI.Demo.Client/Documentation/Components/Overlay/Examples/OverlayTransparent.razor index f0510e176c..b35102d34d 100644 --- a/examples/Demo/FluentUI.Demo.Client/Documentation/Components/Overlay/Examples/OverlayTransparent.razor +++ b/examples/Demo/FluentUI.Demo.Client/Documentation/Components/Overlay/Examples/OverlayTransparent.razor @@ -2,7 +2,7 @@ Show Overlay - + @code { From 412ef59618325744780e9ff85bde1df388ca11c2 Mon Sep 17 00:00:00 2001 From: MarvinKlein1508 Date: Thu, 27 Nov 2025 16:18:00 +0100 Subject: [PATCH 25/36] Update samples --- .../Examples/OverlayBackgroundColor.razor | 6 ++-- .../Overlay/Examples/OverlayDefault.razor | 14 ++++----- .../Overlay/Examples/OverlayFullScreen.razor | 8 ++--- .../Overlay/Examples/OverlayInteractive.razor | 30 +++++++++---------- .../Overlay/Examples/OverlayTimed.razor | 12 ++++---- .../Overlay/Examples/OverlayTransparent.razor | 6 ++-- 6 files changed, 38 insertions(+), 38 deletions(-) diff --git a/examples/Demo/FluentUI.Demo.Client/Documentation/Components/Overlay/Examples/OverlayBackgroundColor.razor b/examples/Demo/FluentUI.Demo.Client/Documentation/Components/Overlay/Examples/OverlayBackgroundColor.razor index 4ee1d44164..90d45d49fa 100644 --- a/examples/Demo/FluentUI.Demo.Client/Documentation/Components/Overlay/Examples/OverlayBackgroundColor.razor +++ b/examples/Demo/FluentUI.Demo.Client/Documentation/Components/Overlay/Examples/OverlayBackgroundColor.razor @@ -1,7 +1,7 @@  Show Overlay - @@ -11,8 +11,8 @@ @code { private bool visible; - protected void HandleOnClose() + private void HandleOnClose() { - //DemoLogger.WriteLine("Custom background color overlay closed"); + Console.WriteLine("Custom background color overlay closed"); } } diff --git a/examples/Demo/FluentUI.Demo.Client/Documentation/Components/Overlay/Examples/OverlayDefault.razor b/examples/Demo/FluentUI.Demo.Client/Documentation/Components/Overlay/Examples/OverlayDefault.razor index b777d5d091..17043853aa 100644 --- a/examples/Demo/FluentUI.Demo.Client/Documentation/Components/Overlay/Examples/OverlayDefault.razor +++ b/examples/Demo/FluentUI.Demo.Client/Documentation/Components/Overlay/Examples/OverlayDefault.razor @@ -1,22 +1,23 @@ @using Microsoft.FluentUI.AspNetCore.Components.Extensions -()) + -()) +

-Show Overlay +Show Overlay + Justification="justification" + OnClose="HandleOnClose"> @@ -25,9 +26,8 @@ private JustifyContent justification = JustifyContent.Center; private HorizontalAlignment alignment = HorizontalAlignment.Center; - private Task ShowOverlay() + private void HandleOnClose() { - visible = !visible; - return Task.CompletedTask; + Console.WriteLine("Overlay closed"); } } diff --git a/examples/Demo/FluentUI.Demo.Client/Documentation/Components/Overlay/Examples/OverlayFullScreen.razor b/examples/Demo/FluentUI.Demo.Client/Documentation/Components/Overlay/Examples/OverlayFullScreen.razor index 14bbf8c571..f11d08fbff 100644 --- a/examples/Demo/FluentUI.Demo.Client/Documentation/Components/Overlay/Examples/OverlayFullScreen.razor +++ b/examples/Demo/FluentUI.Demo.Client/Documentation/Components/Overlay/Examples/OverlayFullScreen.razor @@ -1,20 +1,20 @@  Show Overlay - + PreventScroll="true"> @code { private bool visible; - protected void HandleOnClose() + private void HandleOnClose() { - //DemoLogger.WriteLine("Full screen overlay closed"); + Console.WriteLine("Full screen overlay closed"); } } diff --git a/examples/Demo/FluentUI.Demo.Client/Documentation/Components/Overlay/Examples/OverlayInteractive.razor b/examples/Demo/FluentUI.Demo.Client/Documentation/Components/Overlay/Examples/OverlayInteractive.razor index 7fe42104e6..c18b07a92c 100644 --- a/examples/Demo/FluentUI.Demo.Client/Documentation/Components/Overlay/Examples/OverlayInteractive.razor +++ b/examples/Demo/FluentUI.Demo.Client/Documentation/Components/Overlay/Examples/OverlayInteractive.razor @@ -1,8 +1,8 @@  - - - + + + Counter: @counter - + PreventScroll="true"> @if (interactive) {
@@ -33,7 +33,7 @@ } else { - + } @@ -54,14 +54,14 @@ @code { - bool visible = false; - bool interactive = true; - bool interactiveExceptId = true; - bool fullScreen = true; - int counter = 0; + private bool visible; + private bool interactive = true; + private bool interactiveExceptId = true; + private bool fullScreen = true; + private int counter = 0; - protected void HandleOnClose() + private void HandleOnClose() { - //DemoLogger.WriteLine("Overlay closed"); + Console.WriteLine("Overlay closed"); } } diff --git a/examples/Demo/FluentUI.Demo.Client/Documentation/Components/Overlay/Examples/OverlayTimed.razor b/examples/Demo/FluentUI.Demo.Client/Documentation/Components/Overlay/Examples/OverlayTimed.razor index 640870da2e..9fc71ba5b6 100644 --- a/examples/Demo/FluentUI.Demo.Client/Documentation/Components/Overlay/Examples/OverlayTimed.razor +++ b/examples/Demo/FluentUI.Demo.Client/Documentation/Components/Overlay/Examples/OverlayTimed.razor @@ -1,12 +1,12 @@ @using Microsoft.FluentUI.AspNetCore.Components.Extensions -()) + + @bind-Value="justification" /> -()) + + @bind-Value="alignment" />

@@ -24,10 +24,10 @@ private JustifyContent justification = JustifyContent.Center; private HorizontalAlignment alignment = HorizontalAlignment.Center; - protected async Task HandleOnOpen() + private async Task HandleOnOpen() { visible = true; - //DemoLogger.WriteLine("Overlay opened"); + Console.WriteLine("Overlay opened"); await Task.Delay(3000); visible = false; } diff --git a/examples/Demo/FluentUI.Demo.Client/Documentation/Components/Overlay/Examples/OverlayTransparent.razor b/examples/Demo/FluentUI.Demo.Client/Documentation/Components/Overlay/Examples/OverlayTransparent.razor index b35102d34d..f5204f0e1d 100644 --- a/examples/Demo/FluentUI.Demo.Client/Documentation/Components/Overlay/Examples/OverlayTransparent.razor +++ b/examples/Demo/FluentUI.Demo.Client/Documentation/Components/Overlay/Examples/OverlayTransparent.razor @@ -1,15 +1,15 @@  Show Overlay - + @code { private bool visible; - protected void HandleOnClose() + private void HandleOnClose() { - //DemoLogger.WriteLine("Transparent overlay closed"); + Console.WriteLine("Transparent overlay closed"); } } From 6b5b503570342ebb1a1044a4209cad99064fc381 Mon Sep 17 00:00:00 2001 From: MarvinKlein1508 Date: Thu, 27 Nov 2025 16:19:17 +0100 Subject: [PATCH 26/36] Add gap --- .../Components/Overlay/Examples/OverlayInteractive.razor | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/Demo/FluentUI.Demo.Client/Documentation/Components/Overlay/Examples/OverlayInteractive.razor b/examples/Demo/FluentUI.Demo.Client/Documentation/Components/Overlay/Examples/OverlayInteractive.razor index c18b07a92c..eb2eb70c29 100644 --- a/examples/Demo/FluentUI.Demo.Client/Documentation/Components/Overlay/Examples/OverlayInteractive.razor +++ b/examples/Demo/FluentUI.Demo.Client/Documentation/Components/Overlay/Examples/OverlayInteractive.razor @@ -1,5 +1,5 @@  - + From 5a3e1c79f052e9cd7bac5089e4632c7ab2c7ae41 Mon Sep 17 00:00:00 2001 From: MarvinKlein1508 Date: Thu, 27 Nov 2025 16:52:57 +0100 Subject: [PATCH 27/36] Code review fixes --- .../Components/Overlay/FluentOverlay.razor.cs | 5 +---- ...icrosoft.FluentUI.AspNetCore.Components.csproj | 15 +++++---------- 2 files changed, 6 insertions(+), 14 deletions(-) diff --git a/src/Core/Components/Overlay/FluentOverlay.razor.cs b/src/Core/Components/Overlay/FluentOverlay.razor.cs index 726aeee671..2c63ef3025 100644 --- a/src/Core/Components/Overlay/FluentOverlay.razor.cs +++ b/src/Core/Components/Overlay/FluentOverlay.razor.cs @@ -16,7 +16,6 @@ namespace Microsoft.FluentUI.AspNetCore.Components; public partial class FluentOverlay : FluentComponentBase { private const string JAVASCRIPT_FILE = FluentJSModule.JAVASCRIPT_ROOT + "Overlay/FluentOverlay.razor.js"; - private const string DEFAULT_NEUTRAL_COLOR = "#808080"; private string? _color; private int _r, _g, _b; @@ -130,7 +129,7 @@ public FluentOverlay(LibraryConfiguration configuration) : base(configuration) /// Default NeutralBaseColor token value (#808080). ///
[Parameter] - public string? BackgroundColor { get; set; } + public string BackgroundColor { get; set; } = "#808080"; /// [Parameter] @@ -176,8 +175,6 @@ protected override async Task OnParametersSetAsync() Transparent = false; } - BackgroundColor ??= DEFAULT_NEUTRAL_COLOR; - if (!CheckRGBString().IsMatch(BackgroundColor)) { throw new ArgumentException("BackgroundColor must be a valid HTML hex color string (#rrggbb or #rgb)"); diff --git a/src/Core/Microsoft.FluentUI.AspNetCore.Components.csproj b/src/Core/Microsoft.FluentUI.AspNetCore.Components.csproj index c6485c3ac6..01a3d9630f 100644 --- a/src/Core/Microsoft.FluentUI.AspNetCore.Components.csproj +++ b/src/Core/Microsoft.FluentUI.AspNetCore.Components.csproj @@ -57,11 +57,6 @@ - - - - - @@ -80,7 +75,7 @@ - + @@ -89,9 +84,9 @@ runtime; build; native; contentfiles; analyzers; buildtransitive - all - runtime; build; native; contentfiles; analyzers; buildtransitive - + all + runtime; build; native; contentfiles; analyzers; buildtransitive + @@ -126,7 +121,7 @@ - + From 13448bcc51a24bdb693f7dd153d3179402ac5ed0 Mon Sep 17 00:00:00 2001 From: MarvinKlein1508 Date: Thu, 27 Nov 2025 17:29:20 +0100 Subject: [PATCH 28/36] Specify DotNet.DotNetObject type --- src/Core/Components/Overlay/FluentOverlay.razor.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/Core/Components/Overlay/FluentOverlay.razor.ts b/src/Core/Components/Overlay/FluentOverlay.razor.ts index 96fe92bcc6..5a55c3afe2 100644 --- a/src/Core/Components/Overlay/FluentOverlay.razor.ts +++ b/src/Core/Components/Overlay/FluentOverlay.razor.ts @@ -1,5 +1,7 @@ +import { DotNet } from "../../../Core.Scripts/src/d-ts/Microsoft.JSInterop"; + export namespace Microsoft.FluentUI.Blazor.Overlay { - export function Initialize(dotNetHelper: any, containerId: string, id: string) { + export function Initialize(dotNetHelper: DotNet.DotNetObject, containerId: string, id: string) { const _document = document as any; if (!_document.fluentOverlayData) { From 1ebcc8d1ca0221ea36551883d86d08e5dc0dbecd Mon Sep 17 00:00:00 2001 From: MarvinKlein1508 Date: Thu, 27 Nov 2025 17:31:42 +0100 Subject: [PATCH 29/36] Move into OnInitialized --- .../Components/Overlay/FluentOverlay.razor.cs | 35 +++++++++++-------- 1 file changed, 20 insertions(+), 15 deletions(-) diff --git a/src/Core/Components/Overlay/FluentOverlay.razor.cs b/src/Core/Components/Overlay/FluentOverlay.razor.cs index 2c63ef3025..8a55edfcd3 100644 --- a/src/Core/Components/Overlay/FluentOverlay.razor.cs +++ b/src/Core/Components/Overlay/FluentOverlay.razor.cs @@ -148,23 +148,10 @@ protected override async Task OnAfterRenderAsync(bool firstRender) await JSModule.ImportJavaScriptModuleAsync(JAVASCRIPT_FILE); } } + /// - protected override async Task OnParametersSetAsync() + protected override void OnInitialized() { - if (Interactive && JSModule.Imported) - { - if (Visible) - { - // Add a document.addEventListener when Visible is true - await InvokeOverlayInitializeAsync(); - } - else - { - // Remove a document.addEventListener when Visible is false - await InvokeOverlayDisposeAsync(); - } - } - if (!Transparent && Opacity is null) { Opacity = 0.4; @@ -196,6 +183,24 @@ protected override async Task OnParametersSetAsync() } } + /// + protected override async Task OnParametersSetAsync() + { + if (Interactive && JSModule.Imported) + { + if (Visible) + { + // Add a document.addEventListener when Visible is true + await InvokeOverlayInitializeAsync(); + } + else + { + // Remove a document.addEventListener when Visible is false + await InvokeOverlayDisposeAsync(); + } + } + } + /// [JSInvokable] public async Task OnCloseInteractiveAsync(MouseEventArgs e) From db61322bd4fe62da491fd96b59851f7f83f38d5d Mon Sep 17 00:00:00 2001 From: MarvinKlein1508 Date: Thu, 27 Nov 2025 17:45:50 +0100 Subject: [PATCH 30/36] use HTMLElement --- src/Core/Components/Overlay/FluentOverlay.razor.ts | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/Core/Components/Overlay/FluentOverlay.razor.ts b/src/Core/Components/Overlay/FluentOverlay.razor.ts index 5a55c3afe2..ffe5054241 100644 --- a/src/Core/Components/Overlay/FluentOverlay.razor.ts +++ b/src/Core/Components/Overlay/FluentOverlay.razor.ts @@ -17,8 +17,9 @@ export namespace Microsoft.FluentUI.Blazor.Overlay { // Click event handler clickHandler: async function (event: MouseEvent) { - const isInsideContainer = isClickInsideContainer(event, document.getElementById(containerId)); - const isInsideExcludedElement = !!document.getElementById(id) && isClickInsideContainer(event, document.getElementById(id)); + const containerElement = document.getElementById(containerId) as HTMLElement; + const isInsideContainer = isClickInsideContainer(event, containerElement); + const isInsideExcludedElement = !!containerElement && isClickInsideContainer(event, containerElement); if (isInsideContainer && !isInsideExcludedElement) { dotNetHelper.invokeMethodAsync('OnCloseInteractiveAsync', event); @@ -41,7 +42,7 @@ export namespace Microsoft.FluentUI.Blazor.Overlay { delete _document.fluentOverlayData[id]; } } - function isClickInsideContainer(event: MouseEvent, container: any) { + function isClickInsideContainer(event: MouseEvent, container: HTMLElement) { if (!!container) { const rect = container.getBoundingClientRect(); From bf61d5f7f1251bbad2760e413222e5bd5bcf1ce4 Mon Sep 17 00:00:00 2001 From: MarvinKlein1508 Date: Fri, 28 Nov 2025 09:45:20 +0100 Subject: [PATCH 31/36] Set ZIndex above tooltip --- src/Core/Utilities/ZIndex.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Core/Utilities/ZIndex.cs b/src/Core/Utilities/ZIndex.cs index 6cf6f55800..e9b11a1363 100644 --- a/src/Core/Utilities/ZIndex.cs +++ b/src/Core/Utilities/ZIndex.cs @@ -38,5 +38,5 @@ public static class ZIndex /// /// ZIndex for the component. /// - public static int Overlay { get; set; } = 9900; + public static int Overlay { get; set; } = 99990; } From 06e942bf3194c804392ba00ebe2e03d48ae5ac7e Mon Sep 17 00:00:00 2001 From: MarvinKlein1508 Date: Fri, 28 Nov 2025 10:10:04 +0100 Subject: [PATCH 32/36] Add support for AdditionalAttributes --- src/Core/Components/Overlay/FluentOverlay.razor | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Core/Components/Overlay/FluentOverlay.razor b/src/Core/Components/Overlay/FluentOverlay.razor index a47ba27b23..045cc563a2 100644 --- a/src/Core/Components/Overlay/FluentOverlay.razor +++ b/src/Core/Components/Overlay/FluentOverlay.razor @@ -6,6 +6,7 @@
From b502881c795871bfac0e4e1b8cca4c91fab4ffd9 Mon Sep 17 00:00:00 2001 From: MarvinKlein1508 Date: Fri, 28 Nov 2025 10:11:20 +0100 Subject: [PATCH 33/36] Added first test case --- .../Components/Base/ComponentBaseTests.cs | 1 + .../Overlay/FluentOverlayTests.razor | 33 +++++++++++++++++++ 2 files changed, 34 insertions(+) create mode 100644 tests/Core/Components/Overlay/FluentOverlayTests.razor diff --git a/tests/Core/Components/Base/ComponentBaseTests.cs b/tests/Core/Components/Base/ComponentBaseTests.cs index c52cc60258..395c2892f1 100644 --- a/tests/Core/Components/Base/ComponentBaseTests.cs +++ b/tests/Core/Components/Base/ComponentBaseTests.cs @@ -52,6 +52,7 @@ public class ComponentBaseTests : Bunit.TestContext { typeof(FluentDragContainer<>), Loader.MakeGenericType(typeof(int))}, { typeof(FluentDropZone<>), Loader.MakeGenericType(typeof(int))}, { typeof(FluentTimePicker<>), Loader.MakeGenericType(typeof(DateTime))}, + { typeof(FluentOverlay), Loader.Default.WithRequiredParameter("Visible", true)} }; /// diff --git a/tests/Core/Components/Overlay/FluentOverlayTests.razor b/tests/Core/Components/Overlay/FluentOverlayTests.razor new file mode 100644 index 0000000000..162989abe0 --- /dev/null +++ b/tests/Core/Components/Overlay/FluentOverlayTests.razor @@ -0,0 +1,33 @@ +@using Microsoft.FluentUI.AspNetCore.Components.Utilities +@using Xunit; +@using Microsoft.FluentUI.AspNetCore.Components.Tests.Samples; +@inherits Bunit.TestContext +@code +{ + public FluentOverlayTests() + { + JSInterop.Mode = JSRuntimeMode.Loose; + Services.AddFluentUIComponents(); + } + + [Fact] + public void FluentOverlay_Default() + { + // Arrange + bool onClosedRaised = false; + + // Act + var cut = Render(@ + + + ); + + cut.Find(".fluent-overlay").Click(); + + Assert.True(onClosedRaised); + + // Assert + cut.Verify(); + } +} + From a94657a3a3c39e8d1f118dedf72d8859dda9ecf2 Mon Sep 17 00:00:00 2001 From: MarvinKlein1508 Date: Fri, 28 Nov 2025 12:08:27 +0100 Subject: [PATCH 34/36] Add support for all kind of background-color values --- .../Examples/OverlayBackgroundColor.razor | 4 +- .../Overlay/Examples/OverlayFullScreen.razor | 1 - .../Overlay/Examples/OverlayInteractive.razor | 1 - .../Overlay/Examples/OverlayTimed.razor | 1 - .../Overlay/Examples/OverlayTransparent.razor | 2 +- .../Components/Overlay/FluentOverlay.razor.cs | 38 ++----------------- 6 files changed, 6 insertions(+), 41 deletions(-) diff --git a/examples/Demo/FluentUI.Demo.Client/Documentation/Components/Overlay/Examples/OverlayBackgroundColor.razor b/examples/Demo/FluentUI.Demo.Client/Documentation/Components/Overlay/Examples/OverlayBackgroundColor.razor index 90d45d49fa..050c6a99c0 100644 --- a/examples/Demo/FluentUI.Demo.Client/Documentation/Components/Overlay/Examples/OverlayBackgroundColor.razor +++ b/examples/Demo/FluentUI.Demo.Client/Documentation/Components/Overlay/Examples/OverlayBackgroundColor.razor @@ -2,8 +2,8 @@ Show Overlay diff --git a/examples/Demo/FluentUI.Demo.Client/Documentation/Components/Overlay/Examples/OverlayFullScreen.razor b/examples/Demo/FluentUI.Demo.Client/Documentation/Components/Overlay/Examples/OverlayFullScreen.razor index f11d08fbff..cb02b0911d 100644 --- a/examples/Demo/FluentUI.Demo.Client/Documentation/Components/Overlay/Examples/OverlayFullScreen.razor +++ b/examples/Demo/FluentUI.Demo.Client/Documentation/Components/Overlay/Examples/OverlayFullScreen.razor @@ -2,7 +2,6 @@ Show Overlay Show Overlay diff --git a/examples/Demo/FluentUI.Demo.Client/Documentation/Components/Overlay/Examples/OverlayTransparent.razor b/examples/Demo/FluentUI.Demo.Client/Documentation/Components/Overlay/Examples/OverlayTransparent.razor index f5204f0e1d..9a267145cd 100644 --- a/examples/Demo/FluentUI.Demo.Client/Documentation/Components/Overlay/Examples/OverlayTransparent.razor +++ b/examples/Demo/FluentUI.Demo.Client/Documentation/Components/Overlay/Examples/OverlayTransparent.razor @@ -1,7 +1,7 @@  Show Overlay - + diff --git a/src/Core/Components/Overlay/FluentOverlay.razor.cs b/src/Core/Components/Overlay/FluentOverlay.razor.cs index 8a55edfcd3..97d9f3b7b0 100644 --- a/src/Core/Components/Overlay/FluentOverlay.razor.cs +++ b/src/Core/Components/Overlay/FluentOverlay.razor.cs @@ -3,7 +3,6 @@ // ------------------------------------------------------------------------ using System.Globalization; -using System.Text.RegularExpressions; using Microsoft.AspNetCore.Components; using Microsoft.AspNetCore.Components.Web; using Microsoft.FluentUI.AspNetCore.Components.Extensions; @@ -16,9 +15,6 @@ namespace Microsoft.FluentUI.AspNetCore.Components; public partial class FluentOverlay : FluentComponentBase { private const string JAVASCRIPT_FILE = FluentJSModule.JAVASCRIPT_ROOT + "Overlay/FluentOverlay.razor.js"; - - private string? _color; - private int _r, _g, _b; private DotNetObjectReference? _dotNetHelper; /// @@ -36,7 +32,7 @@ public FluentOverlay(LibraryConfiguration configuration) : base(configuration) /// protected string? StyleValue => DefaultStyleBuilder .AddStyle("cursor", "auto", () => Transparent) - .AddStyle("background-color", string.Create(CultureInfo.InvariantCulture, $"rgba({_r}, {_g}, {_b}, {Opacity})"), () => !Transparent) + .AddStyle("background-color", string.Create(CultureInfo.InvariantCulture, $"color-mix(in srgb, {BackgroundColor} {Opacity}%, transparent)"), () => !Transparent) .AddStyle("cursor", "default", () => !Transparent) .AddStyle("position", FullScreen ? "fixed" : "absolute") .AddStyle("display", "flex") @@ -77,10 +73,10 @@ public FluentOverlay(LibraryConfiguration configuration) : base(configuration) /// /// Gets or sets the opacity of the overlay. - /// Default is 0.4. + /// Default is 40%. /// [Parameter] - public double? Opacity { get; set; } + public int? Opacity { get; set; } = 40; /// /// Gets or sets the alignment of the content to a value. @@ -152,35 +148,10 @@ protected override async Task OnAfterRenderAsync(bool firstRender) /// protected override void OnInitialized() { - if (!Transparent && Opacity is null) - { - Opacity = 0.4; - } - if (Opacity > 0) { Transparent = false; } - - if (!CheckRGBString().IsMatch(BackgroundColor)) - { - throw new ArgumentException("BackgroundColor must be a valid HTML hex color string (#rrggbb or #rgb)"); - } - - _color = BackgroundColor[1..]; - - if (_color.Length == 6) - { - _r = int.Parse(_color[..2], NumberStyles.HexNumber, CultureInfo.InvariantCulture); - _g = int.Parse(_color[2..4], NumberStyles.HexNumber, CultureInfo.InvariantCulture); - _b = int.Parse(_color[4..], NumberStyles.HexNumber, CultureInfo.InvariantCulture); - } - else - { - _r = int.Parse(_color[0..1], NumberStyles.HexNumber, CultureInfo.InvariantCulture); - _g = int.Parse(_color[1..2], NumberStyles.HexNumber, CultureInfo.InvariantCulture); - _b = int.Parse(_color[2..], NumberStyles.HexNumber, CultureInfo.InvariantCulture); - } } /// @@ -265,7 +236,4 @@ private async Task InvokeOverlayDisposeAsync() await JSModule.ObjectReference.InvokeVoidAsync("Microsoft.FluentUI.Blazor.Overlay.overlayDispose", InteractiveExceptId); } } - - [GeneratedRegex("^(?:#(?:[a-fA-F0-9]{6}|[a-fA-F0-9]{3}))", RegexOptions.None, matchTimeoutMilliseconds: 1000)] //Add timeout to prevent ReDoS - private static partial Regex CheckRGBString(); } From 57f539cdd7f6ba7ab6661876a8970aecef505371 Mon Sep 17 00:00:00 2001 From: MarvinKlein1508 Date: Fri, 28 Nov 2025 12:11:36 +0100 Subject: [PATCH 35/36] Update comments and remove OnInitialized --- src/Core/Components/Overlay/FluentOverlay.razor.cs | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/src/Core/Components/Overlay/FluentOverlay.razor.cs b/src/Core/Components/Overlay/FluentOverlay.razor.cs index 97d9f3b7b0..e3dd25bc56 100644 --- a/src/Core/Components/Overlay/FluentOverlay.razor.cs +++ b/src/Core/Components/Overlay/FluentOverlay.razor.cs @@ -121,7 +121,6 @@ public FluentOverlay(LibraryConfiguration configuration) : base(configuration) /// /// Gets or sets the background color. - /// Needs to be formatted as an HTML hex color string (#rrggbb or #rgb) /// Default NeutralBaseColor token value (#808080). /// [Parameter] @@ -145,15 +144,6 @@ protected override async Task OnAfterRenderAsync(bool firstRender) } } - /// - protected override void OnInitialized() - { - if (Opacity > 0) - { - Transparent = false; - } - } - /// protected override async Task OnParametersSetAsync() { From 03b23fc035367b870a59d82adb06cb656a028291 Mon Sep 17 00:00:00 2001 From: Marvin Klein Date: Sat, 29 Nov 2025 16:07:45 +0100 Subject: [PATCH 36/36] Make opacity double again to allow percentage values. --- src/Core/Components/Overlay/FluentOverlay.razor.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Core/Components/Overlay/FluentOverlay.razor.cs b/src/Core/Components/Overlay/FluentOverlay.razor.cs index e3dd25bc56..5f6eb8b7ba 100644 --- a/src/Core/Components/Overlay/FluentOverlay.razor.cs +++ b/src/Core/Components/Overlay/FluentOverlay.razor.cs @@ -76,7 +76,7 @@ public FluentOverlay(LibraryConfiguration configuration) : base(configuration) /// Default is 40%. /// [Parameter] - public int? Opacity { get; set; } = 40; + public double? Opacity { get; set; } = 40; /// /// Gets or sets the alignment of the content to a value.