Skip to content

Commit 0cb7a9d

Browse files
committed
Finalize component
1 parent 21f6f24 commit 0cb7a9d

10 files changed

Lines changed: 284 additions & 145 deletions

File tree

docs/CodeBeam.MudBlazor.Extensions.Docs.Wasm/wwwroot/index.html

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
<link href="https://fonts.googleapis.com/css2?family=Roboto:wght@700;900&display=swap" rel="stylesheet">
1212
<link href="_content/MudBlazor/MudBlazor.min.css" rel="stylesheet" />
1313
<link href="_content/CodeBeam.MudBlazor.Extensions/MudExtensions.min.css" rel="stylesheet" />
14+
<link href="_content/CodeBeam.MudBlazor.Extensions.Code/prism/prism.min.css" rel="stylesheet" />
1415
</head>
1516

1617
<body>
@@ -32,6 +33,7 @@
3233
<script src="_framework/blazor.webassembly.js"></script>
3334
<script src="_content/MudBlazor/MudBlazor.min.js"></script>
3435
<script src="_content/CodeBeam.MudBlazor.Extensions/MudExtensions.min.js"></script>
36+
<script src="_content/CodeBeam.MudBlazor.Extensions.Code/prism/prism.min.js"></script>
3537

3638
<!-- Google tag (gtag.js) -->
3739
<script async src="https://www.googletagmanager.com/gtag/js?id=G-D4FKK70N92"></script>

docs/CodeBeam.MudBlazor.Extensions.Docs/Pages/Components/CodeViewer/CodeViewerPage.razor

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,4 +13,8 @@
1313
<ExampleCard ComponentName="CodeViewer" ExampleName="CodeViewerExample3" Title="Wrap" AliasName="usage" Description="MudCodeViewer can wrap long code lines.">
1414
<CodeViewerExample3 />
1515
</ExampleCard>
16+
17+
<ExampleCard ComponentName="CodeViewer" ExampleName="CodeViewerExample4" Title="Editable" AliasName="usage" Description="MudCodeViewer has ability of basic edits with Editable parameter. Must used with Code parameter (not ChildContent render fragment).">
18+
<CodeViewerExample4 />
19+
</ExampleCard>
1620
</ExamplePage>
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
@namespace MudExtensions.Docs.Examples
2+
3+
<MudGrid>
4+
<MudItem xs="12" sm="8" Class="d-flex flex-column gap-8 align-center justify-center">
5+
<MudCodeViewer Code="@_code" Editable="@_editable" />
6+
</MudItem>
7+
8+
<MudItem xs="12" sm="4">
9+
<MudSwitchM3 @bind-Value="@_editable" Label="Editable" Color="Color.Secondary" />
10+
</MudItem>
11+
</MudGrid>
12+
13+
14+
@code {
15+
private bool _editable = true;
16+
private string _code = """
17+
// This is a sample code as string parameter.
18+
public class MudCodeViewer
19+
{
20+
public string Language { get; set; } = "csharp";
21+
22+
public void Render()
23+
{
24+
Console.WriteLine("MudExtensions Code Viewer");
25+
}
26+
}
27+
""";
28+
}

src/CodeBeam.MudBlazor.Extensions.Code/CodeBeam.MudBlazor.Extensions.Code.csproj

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -10,9 +10,9 @@
1010
<Authors>CodeBeam</Authors>
1111
<Company>CodeBeam</Company>
1212
<Description>
13-
CodeViewer Component for MudBlazor and CodeBeam.MudBlazor.Extensions
14-
Requires CodeBeam.MudBlazor.Extensions.
15-
https://www.nuget.org/packages/CodeBeam.MudBlazor.Extensions
13+
CodeViewer Component for MudBlazor and CodeBeam.MudBlazor.Extensions
14+
Requires CodeBeam.MudBlazor.Extensions.
15+
https://www.nuget.org/packages/CodeBeam.MudBlazor.Extensions
1616
</Description>
1717
<Copyright>CodeBeam OpenSource MIT</Copyright>
1818
<PackageIcon>Mud_Secondary.png</PackageIcon>
@@ -38,7 +38,6 @@
3838
<Pack>True</Pack>
3939
<PackagePath>\</PackagePath>
4040
</None>
41-
<None Include="wwwroot\MudCode.js" />
4241
</ItemGroup>
4342

4443
<ItemGroup>
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
@namespace MudExtensions
2+
@inherits MudComponentBase
3+
@inject IJSRuntime JS
4+
5+
<div class="@Classname" style="@Style">
6+
7+
@if (_header.Value)
8+
{
9+
<div class="@HeaderClassname">
10+
<span class="mud-codeviewer-language">
11+
@Language.ToDescriptionString()
12+
</span>
13+
14+
@if (ShowCopyButton)
15+
{
16+
<MudIconButton Icon="@_copyIcon" Size="Size.Small" Color="Color.Default" OnClick="HandleCopyButtonClickAsync" />
17+
}
18+
</div>
19+
20+
<MudDivider />
21+
}
22+
23+
<div class="mud-codeviewer-body">
24+
@if (!Editable)
25+
{
26+
<pre class="@PreClass">
27+
<code @ref="_codeRef" @key="@(_code.Value + PreClass)" class="@CodeClass">
28+
@if (ChildContent != null)
29+
{
30+
@ChildContent
31+
}
32+
else
33+
{
34+
@_code.Value
35+
}
36+
</code>
37+
</pre>
38+
}
39+
else
40+
{
41+
<div class="mud-codeviewer-editor">
42+
<pre class="@PreClass">
43+
<code @ref="_codeRef" @key="@(_code.Value + PreClass)" class="@CodeClass">
44+
@_code.Value
45+
</code>
46+
</pre>
47+
48+
<textarea @ref="_textAreaRef" class="mud-codeviewer-textarea" @bind="Code" @oninput="OnInput"
49+
spellcheck="false" autocomplete="off" autocorrect="off" autocapitalize="off"></textarea>
50+
</div>
51+
}
52+
53+
@if (!_header.Value && ShowCopyButton)
54+
{
55+
<MudIconButton Class="mud-codeviewer-copy-overlay" Icon="@_copyIcon" Size="Size.Small" Color="Color.Default" OnClick="HandleCopyButtonClickAsync" />
56+
}
57+
</div>
58+
</div>

src/CodeBeam.MudBlazor.Extensions.Code/MudCodeViewer.razor.cs renamed to src/CodeBeam.MudBlazor.Extensions.Code/Components/MudCodeViewer.razor.cs

Lines changed: 78 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -15,11 +15,15 @@ namespace MudExtensions;
1515
public partial class MudCodeViewer : MudComponentBase
1616
{
1717
private ElementReference _codeRef;
18+
private ElementReference _textAreaRef;
1819
private string? _copyIcon = Icons.Material.Filled.ContentCopy;
20+
private bool _shouldHighlight;
21+
private bool _tabEnabled;
1922

2023
private readonly ParameterState<string?> _code;
2124
private readonly ParameterState<bool> _showLineNumbers;
2225
private readonly ParameterState<bool> _wrap;
26+
private readonly ParameterState<bool> _header;
2327
private readonly ParameterState<CodeLanguage> _language;
2428

2529
/// <summary>
@@ -30,13 +34,17 @@ public MudCodeViewer()
3034
using var registerScope = CreateRegisterScope();
3135
_code = registerScope.RegisterParameter<string?>(nameof(Code))
3236
.WithParameter(() => Code)
33-
.WithChangeHandler(ParameterChanged);
37+
.WithChangeHandler(ParameterChanged)
38+
.WithEventCallback(() => CodeChanged);
3439
_showLineNumbers = registerScope.RegisterParameter<bool>(nameof(ShowLineNumbers))
3540
.WithParameter(() => ShowLineNumbers)
3641
.WithChangeHandler(ParameterChanged);
3742
_wrap = registerScope.RegisterParameter<bool>(nameof(Wrap))
3843
.WithParameter(() => Wrap)
3944
.WithChangeHandler(ParameterChanged);
45+
_header = registerScope.RegisterParameter<bool>(nameof(ShowHeader))
46+
.WithParameter(() => ShowHeader)
47+
.WithChangeHandler(ParameterChanged);
4048
_language = registerScope.RegisterParameter<CodeLanguage>(nameof(Language))
4149
.WithParameter(() => Language)
4250
.WithChangeHandler(ParameterChanged);
@@ -58,6 +66,19 @@ public MudCodeViewer()
5866
.AddClass(HeaderClass)
5967
.Build();
6068

69+
/// <summary>
70+
/// Gets the CSS class name representing the current programming language for syntax highlighting.
71+
/// </summary>
72+
protected string CodeClass => $"language-{_language.Value.ToDescriptionString()}";
73+
74+
/// <summary>
75+
/// Gets the CSS class string used for the pre element based on the selected language and line number display settings.
76+
/// </summary>
77+
private string PreClass => new CssBuilder()
78+
.AddClass($"line-numbers language-{_language.Value.ToDescriptionString()}", _showLineNumbers.Value)
79+
.AddClass($"language-{_language.Value.ToDescriptionString()}", !_showLineNumbers.Value)
80+
.Build();
81+
6182
/// <summary>
6283
/// Gets or sets the code snippet to be displayed or processed by the component.
6384
/// </summary>
@@ -72,9 +93,15 @@ public MudCodeViewer()
7293
[Parameter]
7394
public CodeLanguage Language { get; set; } = CodeLanguage.CSharp;
7495

96+
/// <summary>
97+
/// Gets or sets a value indicating whether line numbers are displayed in the code viewer.
98+
/// </summary>
7599
[Parameter]
76100
public bool ShowLineNumbers { get; set; }
77101

102+
/// <summary>
103+
/// Gets or sets a value indicating whether the header is displayed in the code viewer component.
104+
/// </summary>
78105
[Parameter]
79106
public bool ShowHeader { get; set; } = true;
80107

@@ -84,6 +111,15 @@ public MudCodeViewer()
84111
[Parameter]
85112
public string? HeaderClass { get; set; }
86113

114+
/// <summary>
115+
/// Gets or sets the content to be rendered in the header section of the component.
116+
/// </summary>
117+
[Parameter]
118+
public RenderFragment? HeaderContent { get; set; }
119+
120+
/// <summary>
121+
/// Gets or sets a value indicating whether the copy button is displayed in the code viewer component.
122+
/// </summary>
87123
[Parameter]
88124
public bool ShowCopyButton { get; set; } = true;
89125

@@ -106,12 +142,18 @@ public MudCodeViewer()
106142
[Parameter]
107143
public RenderFragment? ChildContent { get; set; }
108144

145+
/// <summary>
146+
/// Gets or sets a value indicating whether the content is editable by the user.
147+
/// </summary>
148+
[Parameter]
149+
public bool Editable { get; set; }
150+
151+
/// <summary>
152+
/// Gets or sets the callback that is invoked when the code value changes.
153+
/// </summary>
154+
[Parameter]
155+
public EventCallback<string?> CodeChanged { get; set; }
109156

110-
private string CodeClass => $"language-{_language.Value.ToDescriptionString()}";
111-
private string PreClass => new CssBuilder()
112-
.AddClass($"line-numbers language-{_language.Value.ToDescriptionString()}", _showLineNumbers.Value)
113-
.AddClass($"language-{_language.Value.ToDescriptionString()}", !_showLineNumbers.Value)
114-
.Build();
115157

116158
/// <summary>
117159
/// Invoked after the component has rendered. Performs post-render logic, such as refreshing data, when the
@@ -123,6 +165,23 @@ protected override async Task OnAfterRenderAsync(bool firstRender)
123165
{
124166
await RefreshAsync();
125167
}
168+
169+
if (Editable && !_tabEnabled)
170+
{
171+
await JS.InvokeVoidAsync("MudCode.enableTabIndent", _textAreaRef);
172+
_tabEnabled = true;
173+
}
174+
175+
if (!Editable)
176+
{
177+
_tabEnabled = false;
178+
}
179+
180+
if (_shouldHighlight)
181+
{
182+
_shouldHighlight = false;
183+
await RefreshAsync();
184+
}
126185
}
127186

128187
/// <summary>
@@ -144,12 +203,19 @@ public async Task CopyAsync()
144203
await JS.InvokeVoidAsync("MudCode.copy", Code);
145204
}
146205

206+
/// <summary>
207+
/// Handles changes to component parameters asynchronously and refreshes the component state.
208+
/// </summary>
147209
protected async Task ParameterChanged()
148210
{
149211
await Task.Delay(1);
150212
await RefreshAsync();
151213
}
152214

215+
/// <summary>
216+
/// Handles the copy button click event asynchronously, updates the copy icon to indicate success, and restores the
217+
/// original icon after a brief delay.
218+
/// </summary>
153219
protected async Task HandleCopyButtonClickAsync()
154220
{
155221
await CopyAsync();
@@ -159,4 +225,10 @@ protected async Task HandleCopyButtonClickAsync()
159225
_copyIcon = Icons.Material.Filled.ContentCopy;
160226
StateHasChanged();
161227
}
228+
229+
private async Task OnInput(ChangeEventArgs e)
230+
{
231+
await _code.SetValueAsync(e.Value?.ToString());
232+
_shouldHighlight = true;
233+
}
162234
}

0 commit comments

Comments
 (0)