Skip to content

Commit 3c4acf5

Browse files
authored
New Component: MudTeleport (#196)
* MudTeleport * MudTeleport Finalize
1 parent b9a188a commit 3c4acf5

File tree

11 files changed

+307
-8
lines changed

11 files changed

+307
-8
lines changed
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
@namespace MudExtensions
2+
@inherits MudComponentBase
3+
4+
<div @ref="_ref" class="@Class" style="@Style">
5+
@ChildContent
6+
</div>
7+
8+
<div class="@_generatedClass @OwnClass">
9+
10+
</div>
11+
Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
using Microsoft.AspNetCore.Components;
2+
using Microsoft.JSInterop;
3+
using MudBlazor;
4+
using MudBlazor.Utilities;
5+
using MudExtensions.Utilities;
6+
7+
namespace MudExtensions
8+
{
9+
public partial class MudTeleport : MudComponentBase
10+
{
11+
[Inject] MudTeleportManager MudTeleportManager { get; set; }
12+
13+
private string _generatedClass = "teleport" + Guid.NewGuid().ToString().Substring(0, 8);
14+
15+
protected string Classname => new CssBuilder()
16+
.AddClass(_generatedClass)
17+
.AddClass(Class)
18+
.Build();
19+
20+
/// <summary>
21+
/// The class name that shows the parent which the teleport content will teleport.
22+
/// </summary>
23+
[Parameter] public string To { get; set; }
24+
25+
/// <summary>
26+
/// The class name that used to return teleport content to the container.
27+
/// </summary>
28+
[Parameter] public string OwnClass { get; set; }
29+
30+
/// <summary>
31+
/// If true teleported content returns the container, otherwise the content remains the last teleported place. Default is false.
32+
/// </summary>
33+
[Parameter] public bool ReturnWhenNotFound { get; set; }
34+
35+
[Parameter] public RenderFragment ChildContent { get; set; }
36+
37+
private ElementReference _ref;
38+
39+
private string _to;
40+
private bool _mustUpdate = true;
41+
42+
protected override void OnParametersSet()
43+
{
44+
// if `To` or `Disabled` has changed we must update the teleport
45+
if (To != null && (!To.Equals(_to)))
46+
{
47+
_to = To;
48+
_mustUpdate = true;
49+
}
50+
else
51+
{
52+
_mustUpdate = false;
53+
}
54+
}
55+
56+
protected override async Task OnAfterRenderAsync(bool firstRender)
57+
{
58+
if (_mustUpdate)
59+
{
60+
await Update();
61+
}
62+
await base.OnAfterRenderAsync(firstRender);
63+
}
64+
65+
public async Task Update()
66+
{
67+
var result = await MudTeleportManager.Teleport(_ref, To);
68+
if (result == "not found" && ReturnWhenNotFound == true)
69+
{
70+
await MudTeleportManager.Teleport(_ref, _generatedClass);
71+
}
72+
}
73+
74+
public async Task Reset()
75+
{
76+
To = null;
77+
await MudTeleportManager.Teleport(_ref, _generatedClass);
78+
StateHasChanged();
79+
}
80+
81+
public async ValueTask DisposeAsync()
82+
{
83+
try
84+
{
85+
await MudTeleportManager.RemoveFromDom(_ref);
86+
}
87+
catch (JSDisconnectedException) { }
88+
catch (TaskCanceledException) { }
89+
catch (InvalidOperationException) { /* it throws in the server side project */ }
90+
}
91+
}
92+
}

CodeBeam.MudBlazor.Extensions/Services/ExtensionServiceCollectionExtensions.cs

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,4 @@
1-
using System;
2-
using System.Diagnostics.CodeAnalysis;
3-
using Microsoft.AspNetCore.Components;
1+
using System.Diagnostics.CodeAnalysis;
42
using Microsoft.Extensions.DependencyInjection;
53
using Microsoft.Extensions.DependencyInjection.Extensions;
64
using MudBlazor.Services;
@@ -22,7 +20,7 @@ public static IServiceCollection AddScrollManagerExtended(this IServiceCollectio
2220
}
2321

2422
/// <summary>
25-
/// Adds ScrollManagerExtended as a transient instance.
23+
/// Adds CssManager as a transient instance.
2624
/// </summary>
2725
/// <param name="services">IServiceCollection</param>
2826
public static IServiceCollection AddMudCssManager(this IServiceCollection services)
@@ -31,6 +29,12 @@ public static IServiceCollection AddMudCssManager(this IServiceCollection servic
3129
return services;
3230
}
3331

32+
public static IServiceCollection AddMudTeleportManager(this IServiceCollection services)
33+
{
34+
services.TryAddTransient<MudTeleportManager>();
35+
return services;
36+
}
37+
3438
/// <summary>
3539
/// Adds common services required by MudBlazor components
3640
/// </summary>
@@ -42,7 +46,8 @@ public static IServiceCollection AddMudExtensions(this IServiceCollection servic
4246
configuration ??= new MudServicesConfiguration();
4347
return services
4448
.AddScrollManagerExtended()
45-
.AddMudCssManager();
49+
.AddMudCssManager()
50+
.AddMudTeleportManager();
4651
}
4752

4853
/// <summary>
@@ -59,7 +64,8 @@ public static IServiceCollection AddMudExtensions(this IServiceCollection servic
5964
configuration(options);
6065
return services
6166
.AddScrollManagerExtended()
62-
.AddMudCssManager();
67+
.AddMudCssManager()
68+
.AddMudTeleportManager();
6369
}
6470
}
6571
}

CodeBeam.MudBlazor.Extensions/TScripts/MudExtensions.js

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,4 +27,21 @@ function setcss(classe, cssprop, value) {
2727
for (let i = 0; i < elements.length; i++) {
2828
elements[i].style.setProperty(cssprop, value);
2929
}
30-
}
30+
}
31+
32+
33+
window.mudTeleport = {
34+
teleport: (source, to) => {
35+
const target = document.querySelector(to);
36+
if (!target) {
37+
//throw new Error(`teleport: ${to} is not found on the DOM`);
38+
return "not found";
39+
}
40+
target.appendChild(source);
41+
return "ok";
42+
},
43+
44+
removeFromDOM: (el) => {
45+
if (el && el.__internalId !== null) el.remove();
46+
},
47+
};
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
using Microsoft.AspNetCore.Components;
2+
using Microsoft.JSInterop;
3+
4+
namespace MudExtensions.Utilities
5+
{
6+
public class MudTeleportManager
7+
{
8+
private IJSRuntime JSRuntime;
9+
10+
public MudTeleportManager(IJSRuntime jsRuntime)
11+
{
12+
JSRuntime = jsRuntime;
13+
}
14+
15+
public async Task<string> Teleport(ElementReference reference, string toTeleport)
16+
{
17+
if (string.IsNullOrEmpty(toTeleport))
18+
{
19+
return null;
20+
}
21+
if (toTeleport.StartsWith('.') == false)
22+
{
23+
toTeleport = "." + toTeleport;
24+
}
25+
var result = await JSRuntime.InvokeAsync<string>("mudTeleport.teleport", reference, toTeleport);
26+
return result;
27+
}
28+
29+
public async Task RemoveFromDom(ElementReference reference)
30+
{
31+
await JSRuntime.InvokeVoidAsync("mudTeleport.removeFromDOM", reference);
32+
}
33+
34+
}
35+
}

CodeBeam.MudBlazor.Extensions/wwwroot/MudExtensions.min.js

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

ComponentViewer.Docs/Pages/Components/ApiPage.razor

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -515,6 +515,27 @@
515515
</MudTable>
516516
</ExampleCard>
517517

518+
<ExampleCard Title="Api - MudTeleport" HasExpansionPanel="true">
519+
<MudTable Items="@(typeof(MudTeleport).GetProperties().Where(x => x.Name != "FieldId" && x.Name != "UserAttributes").OrderBy(x => x.Name).ToList())">
520+
<HeaderContent>
521+
<MudTh>Name</MudTh>
522+
<MudTh>Type</MudTh>
523+
<MudTh>Default</MudTh>
524+
</HeaderContent>
525+
<RowTemplate>
526+
<MudTd DataLabel="Name">@context.Name</MudTd>
527+
<MudTd DataLabel="Type">@context.PropertyType.Name</MudTd>
528+
<MudTd DataLabel="Default">
529+
@if (true)
530+
{
531+
MudTeleport instance = new();
532+
<MudText Typo="Typo.body2">@(context.GetValue(instance)?.ToString() ?? "null")</MudText>
533+
}
534+
</MudTd>
535+
</RowTemplate>
536+
</MudTable>
537+
</ExampleCard>
538+
518539
<ExampleCard Title="Api - MudTextFieldExtended" HasExpansionPanel="true">
519540
<MudTable Items="@(typeof(MudTextFieldExtended<string>).GetProperties().Where(x => x.Name != "FieldId" && x.Name != "UserAttributes").OrderBy(x => x.Name).ToList())">
520541
<HeaderContent>
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
@page "/mudteleport"
2+
@using ComponentViewer.Docs.Pages.Examples
3+
4+
<ExamplePage Title="MudTeleport">
5+
<ExampleCard ExampleName="TeleportExample1" Title="Usage" Description="MudTeleport teleports the content to the specified parent.">
6+
<TeleportExample1 />
7+
</ExampleCard>
8+
</ExamplePage>
Lines changed: 107 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,107 @@
1+
<MudGrid>
2+
<MudItem xs="12" sm="8" >
3+
<div class="d-flex flex-wrap gap-4 align-center justify-space-between">
4+
<MudCard Style="height: 280px; width: 240px">
5+
<MudCardHeader Class="mud-theme-primary">
6+
<MudText>Area: id1</MudText>
7+
</MudCardHeader>
8+
9+
<MudCardContent Class="id1">
10+
<MudText Class="mb-4">Teleported content shows below me</MudText>
11+
<MudDivider />
12+
</MudCardContent>
13+
</MudCard>
14+
15+
<MudCard Style="height: 280px; width: 240px">
16+
<MudCardHeader Class="mud-theme-secondary">
17+
<MudText>Area: id2</MudText>
18+
</MudCardHeader>
19+
20+
<MudCardContent Class="id2 d-flex flex-column align-center justify-center">
21+
<MudButton Class="mb-4" Variant="Variant.Filled" Color="Color.Primary" OnClick="@ToggleOpen">Open Popover</MudButton>
22+
<MudPopover Open="@_isOpen" Fixed="true" Class="id2-popover d-flex flex-column justify-center" Style="width: 300px">
23+
<MudButton OnClick="@ToggleOpen" Class="my-4" Color="Color.Error">Close</MudButton>
24+
</MudPopover>
25+
</MudCardContent>
26+
</MudCard>
27+
28+
<MudCard Style="height: 280px; width: 240px">
29+
<MudCardHeader Class="mud-theme-tertiary">
30+
<MudText>Area: id3</MudText>
31+
</MudCardHeader>
32+
33+
<MudCardContent>
34+
<div class="id3">
35+
36+
</div>
37+
<MudDivider />
38+
<MudText>Teleported content shows above me</MudText>
39+
</MudCardContent>
40+
</MudCard>
41+
</div>
42+
43+
<MudCard Class="mt-4">
44+
<MudCardHeader Class="mud-theme-info">
45+
<MudText>Teleport Container</MudText>
46+
</MudCardHeader>
47+
48+
<MudCardContent>
49+
<MudTeleport @ref="_teleport" To="@_id" ReturnWhenNotFound="_returnWhenNotFound" OwnClass="@_ownClass">
50+
<div class="d-flex flex-column align-center justify-center my-4">
51+
<MudText Align="Align.Center">@(_id == null || _id == "teleport" ? "Waiting for teleport" : "Teleported text")</MudText>
52+
<MudButton OnClick="Teleport" Variant="Variant.Filled">Teleport</MudButton>
53+
@if (_id == "id2" || _id == ".id2")
54+
{
55+
<MudButton Class="mt-2" OnClick="TeleportIntoPopover" Color="Color.Info" Variant="Variant.Filled">Teleport Into Popover</MudButton>
56+
}
57+
</div>
58+
</MudTeleport>
59+
</MudCardContent>
60+
</MudCard>
61+
62+
</MudItem>
63+
64+
<MudItem xs="12" sm="4">
65+
<MudStack Spacing="4">
66+
<MudTextFieldExtended @bind-Value="_id" Label="To" Immediate="true" autocomplete="new-password" Variant="Variant.Outlined" />
67+
<MudSwitchM3 @bind-Checked="_returnWhenNotFound" Label="Return When Not Found" Color="Color.Secondary" />
68+
<MudTextFieldExtended @bind-Value="_ownClass" Label="Own Class" Immediate="true" Variant="Variant.Outlined" />
69+
<MudButton Variant="Variant.Outlined" Color="Color.Secondary" OnClick="@(async() => { _id = null; await _teleport.Reset(); })">Reset</MudButton>
70+
</MudStack>
71+
</MudItem>
72+
</MudGrid>
73+
74+
@code{
75+
MudTeleport _teleport;
76+
string _id;
77+
bool _returnWhenNotFound = false;
78+
string _ownClass;
79+
80+
private void Teleport()
81+
{
82+
if (_id != null && _id.Contains("id2"))
83+
{
84+
_id = "id3";
85+
}
86+
else if (_id == "id1" || _id == ".id1")
87+
{
88+
_id = "id2";
89+
}
90+
else
91+
{
92+
_id = "id1";
93+
}
94+
}
95+
96+
private void TeleportIntoPopover()
97+
{
98+
_id = "id2-popover";
99+
}
100+
101+
public bool _isOpen;
102+
103+
public void ToggleOpen()
104+
{
105+
_isOpen = !_isOpen;
106+
}
107+
}

ComponentViewer.Docs/Pages/Index.razor

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -236,6 +236,7 @@
236236
new("MudSplitter", "A resizeable content splitter."),
237237
new("MudStepper", "A wizard-like steps to control the flow with rich options."),
238238
new("MudSwitchM3", "Material 3 switch component that has all MudBlazor features."),
239+
new("MudTeleport", "Teleport the content to the specified parent and not follow the DOM hierarchy."),
239240
new("MudTransferList", "A component that has 2 lists that transfer items to another."),
240241
new("MudWatch", "A performance optimized watch to show current time or show stopwatch or countdown."),
241242
new("MudWheel", "Smoothly changes values in a wheel within defined ItemCollection."),

0 commit comments

Comments
 (0)