44
55using Microsoft . AspNetCore . Components ;
66using Microsoft . AspNetCore . Components . Routing ;
7+ using Microsoft . FluentUI . AspNetCore . Components . Extensions ;
8+ using Microsoft . JSInterop ;
79
810namespace Microsoft . FluentUI . AspNetCore . Components ;
911
10- public partial class FluentDialogProvider : IDisposable
12+ public partial class FluentDialogProvider : IAsyncDisposable
1113{
14+ private const string JAVASCRIPT_FILE = "./_content/Microsoft.FluentUI.AspNetCore.Components/Components/Dialog/FluentDialogProvider.razor.js" ;
15+
1216 private readonly InternalDialogContext _internalDialogContext ;
1317 private readonly RenderFragment _renderDialogs ;
18+ private IJSObjectReference ? _module ;
1419
1520 [ Inject ]
1621 private IDialogService DialogService { get ; set ; } = default ! ;
1722
1823 [ Inject ]
1924 private NavigationManager NavigationManager { get ; set ; } = default ! ;
2025
26+ [ Inject ]
27+ private IJSRuntime JSRuntime { get ; set ; } = default ! ;
28+
29+ [ Inject ]
30+ private LibraryConfiguration LibraryConfiguration { get ; set ; } = default ! ;
31+
2132 /// <summary>
2233 /// Constructs an instance of <see cref="FluentToastProvider"/>.
2334 /// </summary>
@@ -40,20 +51,43 @@ protected override void OnInitialized()
4051 DialogService . OnDialogCloseRequested += DismissInstance ;
4152 }
4253
54+ protected override async Task OnAfterRenderAsync ( bool firstRender )
55+ {
56+ if ( firstRender )
57+ {
58+ _module ??= await JSRuntime . InvokeAsync < IJSObjectReference > ( "import" , JAVASCRIPT_FILE . FormatCollocatedUrl ( LibraryConfiguration ) ) ;
59+ }
60+ }
61+
4362 private void ShowDialog ( IDialogReference dialogReference , Type ? dialogComponent , DialogParameters parameters , object content )
4463 {
45- DialogInstance dialog = new ( dialogComponent , parameters , content ) ;
46- dialogReference . Instance = dialog ;
64+ if ( _module is null )
65+ {
66+ throw new InvalidOperationException ( "JS module is not loaded." ) ;
67+ }
4768
48- _internalDialogContext . References . Add ( dialogReference ) ;
49- InvokeAsync ( StateHasChanged ) ;
69+ InvokeAsync ( async ( ) =>
70+ {
71+ var previouslyFocusedElement = await _module . InvokeAsync < IJSObjectReference > ( "getActiveElement" ) ;
72+ DialogInstance dialog = new ( dialogComponent , parameters , content , previouslyFocusedElement ) ;
73+ dialogReference . Instance = dialog ;
74+
75+ _internalDialogContext . References . Add ( dialogReference ) ;
76+ } ) ;
5077 }
5178
5279 private async Task < IDialogReference > ShowDialogAsync ( IDialogReference dialogReference , Type ? dialogComponent , DialogParameters parameters , object content )
5380 {
54- return await Task . Run ( ( ) =>
81+ if ( _module is null )
5582 {
56- DialogInstance dialog = new ( dialogComponent , parameters , content ) ;
83+ throw new InvalidOperationException ( "JS module is not loaded." ) ;
84+ }
85+
86+ return await Task . Run ( async ( ) =>
87+ {
88+ var previouslyFocusedElement = await _module . InvokeAsync < IJSObjectReference > ( "getActiveElement" ) ;
89+
90+ DialogInstance dialog = new ( dialogComponent , parameters , content , previouslyFocusedElement ) ;
5791 dialogReference . Instance = dialog ;
5892
5993 _internalDialogContext . References . Add ( dialogReference ) ;
@@ -130,6 +164,17 @@ internal void DismissInstance(string id, DialogResult result)
130164 }
131165 }
132166
167+ internal async Task ReturnFocusAsync ( IJSObjectReference element )
168+ {
169+ if ( _module is null )
170+ {
171+ throw new InvalidOperationException ( "JS module is not loaded." ) ;
172+ }
173+
174+ await _module . InvokeVoidAsync ( "focusElement" , element ) ;
175+ await element . DisposeAsync ( ) ;
176+ }
177+
133178 internal IDialogReference ? GetDialogReference ( string id )
134179 {
135180 return _internalDialogContext . References . SingleOrDefault ( x => x . Id == id ) ;
@@ -183,11 +228,25 @@ private async Task OnDismissAsync(DialogEventArgs args)
183228 }
184229 }
185230
186- public void Dispose ( )
231+ public async ValueTask DisposeAsync ( )
187232 {
188233 if ( NavigationManager != null )
189234 {
190235 NavigationManager . LocationChanged -= LocationChanged ;
191236 }
237+
238+ try
239+ {
240+ if ( _module is not null )
241+ {
242+ await _module . DisposeAsync ( ) ;
243+ }
244+ }
245+ catch ( Exception ex ) when ( ex is JSDisconnectedException ||
246+ ex is OperationCanceledException )
247+ {
248+ // The JSRuntime side may routinely be gone already if the reason we're disposing is that
249+ // the client disconnected. This is not an error.
250+ }
192251 }
193252}
0 commit comments