diff --git a/src/BootstrapBlazor.Server/BootstrapBlazor.Server.csproj b/src/BootstrapBlazor.Server/BootstrapBlazor.Server.csproj
index ce9d5f0920e..e2390bb028e 100644
--- a/src/BootstrapBlazor.Server/BootstrapBlazor.Server.csproj
+++ b/src/BootstrapBlazor.Server/BootstrapBlazor.Server.csproj
@@ -71,6 +71,7 @@
+
diff --git a/src/BootstrapBlazor.Server/Components/Samples/CherryMarkdowns.razor b/src/BootstrapBlazor.Server/Components/Samples/CherryMarkdowns.razor
index 9c7a9eaaf80..efe9fb25705 100644
--- a/src/BootstrapBlazor.Server/Components/Samples/CherryMarkdowns.razor
+++ b/src/BootstrapBlazor.Server/Components/Samples/CherryMarkdowns.razor
@@ -3,6 +3,9 @@
@Localizer["Header"]
@Localizer["Tip"]
+
+
+
@((MarkupString)Localizer["MarkdownsNote"].Value)
builder.Services.Configure<HubOptions>(option => option.MaximumReceiveMessageSize = null);
diff --git a/src/BootstrapBlazor.Server/Components/Samples/Vditors.razor b/src/BootstrapBlazor.Server/Components/Samples/Vditors.razor
new file mode 100644
index 00000000000..f975d959e4c
--- /dev/null
+++ b/src/BootstrapBlazor.Server/Components/Samples/Vditors.razor
@@ -0,0 +1,54 @@
+@page "/vditor"
+@inject IOptionsMonitor WebsiteOption
+
+@Localizer["VditorTitle"]
+
+@Localizer["VditorSubTitle"]
+
+
+
+@((MarkupString)Localizer["MarkdownsNote"].Value)
+
+builder.Services.Configure<HubOptions>(option => option.MaximumReceiveMessageSize = null);
+
+
+
+
+
+
+
+ @foreach (var item in Enum.GetValues(typeof(VditorMode)).Cast())
+ {
+
+ }
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/BootstrapBlazor.Server/Components/Samples/Vditors.razor.cs b/src/BootstrapBlazor.Server/Components/Samples/Vditors.razor.cs
new file mode 100644
index 00000000000..70f0c4d0545
--- /dev/null
+++ b/src/BootstrapBlazor.Server/Components/Samples/Vditors.razor.cs
@@ -0,0 +1,195 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the Apache 2.0 License
+// See the LICENSE file in the project root for more information.
+// Maintainer: Argo Zhang(argo@live.ca) Website: https://www.blazor.zone
+
+namespace BootstrapBlazor.Server.Components.Samples;
+
+///
+/// Vditors 组件示例代码
+///
+public partial class Vditors
+{
+ [Inject]
+ [NotNull]
+ private IStringLocalizer? Localizer { get; set; }
+
+ private VditorOptions _vditorOptions = new()
+ {
+ Height = "500px"
+ };
+
+ private Vditor _vditor = default!;
+ private string? _htmlString;
+ private string _vditorValueString = "## 所见即所得(WYSIWYG)\n所见即所得模式对不熟悉 Markdown 的用户较为友好,熟悉 Markdown 的话也可以无缝使用。";
+ private VditorMode _mode = VditorMode.WYSIWYG;
+ private ConsoleLogger _logger = default!;
+
+ private async Task OnModeChanged(VditorMode mode)
+ {
+ _mode = mode;
+ _vditorOptions.Mode = mode;
+ if (mode == VditorMode.WYSIWYG)
+ {
+ _vditorValueString = "## 所见即所得(WYSIWYG)\n所见即所得模式对不熟悉 Markdown 的用户较为友好,熟悉 Markdown 的话也可以无缝使用。";
+ }
+ else if (mode == VditorMode.IR)
+ {
+ _vditorValueString = "## 即时渲染(IR)\n即时渲染模式对熟悉 Typora 的用户应该不会感到陌生,理论上这是最优雅的 Markdown 编辑方式。";
+ }
+ else if (mode == VditorMode.SV)
+ {
+ _vditorValueString = "## 分屏预览(SV)\n传统的分屏预览模式适合大屏下的 Markdown 编辑。";
+ }
+
+ _htmlString = await _vditor.GetHtmlAsync();
+ StateHasChanged();
+ }
+
+ private Task OnRenderAsync()
+ {
+ _logger.Log($"Trigger OnRenderAsync");
+ return Task.CompletedTask;
+ }
+
+ private Task OnFocusAsync(string value)
+ {
+ _logger.Log($"Trigger OnFocusAsync");
+ return Task.CompletedTask;
+ }
+
+ private async Task OnBlurAsync(string value)
+ {
+ _vditorValueString = value;
+ _logger.Log($"Trigger OnBlurAsync");
+
+ _htmlString = await _vditor.GetHtmlAsync();
+ StateHasChanged();
+ }
+
+ private Task OnEscapeAsync(string value)
+ {
+ _logger.Log($"Trigger OnEscapeAsync");
+ return Task.CompletedTask;
+ }
+
+ private Task OnSelectAsync(string value)
+ {
+ _logger.Log($"Trigger OnSelectAsync");
+ return Task.CompletedTask;
+ }
+
+ private async Task OnInputAsync(string value)
+ {
+ _vditorValueString = value;
+ _htmlString = await _vditor.GetHtmlAsync();
+
+ _logger.Log($"Trigger OnInputAsync");
+ StateHasChanged();
+ }
+
+ private async Task OnCtrlEnterAsync(string value)
+ {
+ _vditorValueString = value;
+ _htmlString = await _vditor.GetHtmlAsync();
+
+ _logger.Log($"Trigger OnCtrlEnterAsync");
+ StateHasChanged();
+ }
+
+ private async Task OnTriggerGetValueAsync()
+ {
+ _vditorValueString = await _vditor.GetValueAsync() ?? "";
+ }
+
+ private async Task OnTriggerInsertValueAsync()
+ {
+ await _vditor.InsertValueAsync("光标处插入当前值");
+ }
+
+ private async Task OnTriggerGetHtmlAsync()
+ {
+ _htmlString = await _vditor.GetHtmlAsync();
+ }
+
+ private async Task OnTriggerGetSelectionAsync()
+ {
+ var selection = await _vditor.GetSelectionAsync() ?? "";
+ _logger.Log($"Trigger OnTriggerGetSelectionAsync: {selection}");
+ }
+
+ private bool _isDisabled = false;
+ private async Task OnTriggerEnableAsync()
+ {
+ await _vditor.EnableAsync();
+ _isDisabled = false;
+ }
+
+ private async Task OnTriggerDisableAsync()
+ {
+ await _vditor.DisableAsync();
+ _isDisabled = true;
+ }
+
+ private async Task OnTriggerFocusAsync()
+ {
+ await _vditor.FocusAsync();
+ }
+
+ private async Task OnTriggerBlurAsync()
+ {
+ await _vditor.BlurAsync();
+ }
+
+ private static AttributeItem[] GetAttributes() =>
+ [
+ new()
+ {
+ Name = "EditorSettings",
+ Description = "编辑器设置",
+ Type = "EditorSettings",
+ ValueList = " — ",
+ DefaultValue = " — "
+ },
+ new()
+ {
+ Name = "ToolbarSettings",
+ Description = "工具栏设置",
+ Type = "ToolbarSettings",
+ ValueList = " — ",
+ DefaultValue = " — "
+ },
+ new()
+ {
+ Name = "Value",
+ Description = "组件值",
+ Type = "string",
+ ValueList = " — ",
+ DefaultValue = " — "
+ },
+ new()
+ {
+ Name = "Html",
+ Description = "组件 Html 代码",
+ Type = "string",
+ ValueList = " — ",
+ DefaultValue = " — "
+ },
+ new()
+ {
+ Name = "OnFileUpload",
+ Description = "文件上传回调方法",
+ Type = "Func>",
+ ValueList = " — ",
+ DefaultValue = " — "
+ },
+ new()
+ {
+ Name = "IsViewer",
+ Description = "组件是否为浏览器模式",
+ Type = "bool",
+ ValueList = "true/false",
+ DefaultValue = "false"
+ }
+ ];
+}
diff --git a/src/BootstrapBlazor.Server/Extensions/MenusLocalizerExtensions.cs b/src/BootstrapBlazor.Server/Extensions/MenusLocalizerExtensions.cs
index 54f284ce7d1..f4d62ae880c 100644
--- a/src/BootstrapBlazor.Server/Extensions/MenusLocalizerExtensions.cs
+++ b/src/BootstrapBlazor.Server/Extensions/MenusLocalizerExtensions.cs
@@ -516,6 +516,12 @@ void AddForm(DemoMenuItem item)
{
Text = Localizer["ValidateForm"],
Url = "validate-form"
+ },
+ new()
+ {
+ IsNew = true,
+ Text = Localizer["Vditor"],
+ Url = "vditor"
}
};
AddBadge(item);
diff --git a/src/BootstrapBlazor.Server/Locales/en-US.json b/src/BootstrapBlazor.Server/Locales/en-US.json
index 5e7e872e03f..84c5e7d3094 100644
--- a/src/BootstrapBlazor.Server/Locales/en-US.json
+++ b/src/BootstrapBlazor.Server/Locales/en-US.json
@@ -4948,7 +4948,8 @@
"ButtonUpload": "ButtonUpload",
"AvatarUpload": "AvatarUpload",
"CardUpload": "CardUpload",
- "DropUpload": "DropUpload"
+ "DropUpload": "DropUpload",
+ "Vditor": "Vditor Markdown"
},
"BootstrapBlazor.Server.Components.Samples.Table.TablesHeader": {
"TablesHeaderTitle": "Header grouping function",
@@ -7190,5 +7191,11 @@
"AudioDevicePauseText": "Pause",
"AudioDeviceResumeText": "Resume",
"AudioDeviceDownloadText": "Download"
+ },
+ "BootstrapBlazor.Server.Components.Samples.Vditors": {
+ "VditorTitle": "Vditor Markdown",
+ "VditorSubTitle": "Vditor is a browser-based Markdown editor that supports WYSIWYG, instant rendering (similar to Typora), and split-screen preview mode.",
+ "BaseUsageTitle": "Basic usage",
+ "BaseUsageIntro": "Set the content displayed by the component by setting the Value value, and set the component configuration information by setting the Options parameter"
}
}
diff --git a/src/BootstrapBlazor.Server/Locales/zh-CN.json b/src/BootstrapBlazor.Server/Locales/zh-CN.json
index bfe6a152588..ce049b4a6c7 100644
--- a/src/BootstrapBlazor.Server/Locales/zh-CN.json
+++ b/src/BootstrapBlazor.Server/Locales/zh-CN.json
@@ -4948,7 +4948,8 @@
"ButtonUpload": "按钮上传组件 ButtonUpload",
"AvatarUpload": "头像上传组件 AvatarUpload",
"CardUpload": "卡片上传组件 CardUpload",
- "DropUpload": "拖动上传组件 DropUpload"
+ "DropUpload": "拖动上传组件 DropUpload",
+ "Vditor": "富文本框 Vditor Markdown"
},
"BootstrapBlazor.Server.Components.Samples.Table.TablesHeader": {
"TablesHeaderTitle": "表头分组功能",
@@ -7190,5 +7191,11 @@
"AudioDevicePauseText": "暂停",
"AudioDeviceResumeText": "恢复",
"AudioDeviceDownloadText": "下载"
+ },
+ "BootstrapBlazor.Server.Components.Samples.Vditors": {
+ "VditorTitle": "Vditor Markdown 富文本编辑框",
+ "VditorSubTitle": "Vditor 是一款浏览器端的 Markdown 编辑器,支持所见即所得、即时渲染(类似 Typora)和分屏预览模式",
+ "BaseUsageTitle": "基本用法",
+ "BaseUsageIntro": "通过设置 Value 值设置组件显示的内容,通过 Options 参数设置组件配置信息"
}
}
diff --git a/src/BootstrapBlazor.Server/docs.json b/src/BootstrapBlazor.Server/docs.json
index 183ef5c10ae..118f42ad254 100644
--- a/src/BootstrapBlazor.Server/docs.json
+++ b/src/BootstrapBlazor.Server/docs.json
@@ -239,7 +239,8 @@
"video-device": "VideoDevices",
"audio-device": "AudioDevices",
"fullscreen-button": "FullScreenButtons",
- "meet": "Meets"
+ "meet": "Meets",
+ "vditor": "Vditors"
},
"video": {
"table": "BV1ap4y1x7Qn?p=1",
diff --git a/test/UnitTest/Performance/RecordTest.cs b/test/UnitTest/Performance/RecordTest.cs
index 609b091aaf1..831aa175c8a 100644
--- a/test/UnitTest/Performance/RecordTest.cs
+++ b/test/UnitTest/Performance/RecordTest.cs
@@ -23,6 +23,25 @@ public void With_Ok()
Assert.NotEqual(foo3, foo2);
}
+ [Fact]
+ public void Height_Ok()
+ {
+ var dummy1 = new Dummy { Height = 100 };
+ var dummy2 = new Dummy { Height = 100 };
+
+ Assert.Equal(dummy1, dummy2);
+
+ dummy2.Width = 100;
+ Assert.NotEqual(dummy1, dummy2);
+ }
+
+ struct Dummy
+ {
+ public int Height { get; set; }
+
+ public int Width { get; set; }
+ }
+
record Foo
{
public Foo(string name) { Name = name; }