From fbd30633cc95ddaa243093b3dd1d86b28a282d66 Mon Sep 17 00:00:00 2001 From: Saleh Yusefnejad <msynk@outlook.com> Date: Mon, 17 Mar 2025 17:00:08 +0330 Subject: [PATCH 1/2] add BitMarkdownEditor component #10230 --- .../MarkdownEditor/BitMarkdownEditor.razor | 11 + .../MarkdownEditor/BitMarkdownEditor.razor.cs | 34 ++ .../MarkdownEditor/BitMarkdownEditor.scss | 12 + .../MarkdownEditor/BitMarkdownEditor.ts | 351 ++++++++++++++++++ .../BitMarkdownEditorJsRuntimeExtensions.cs | 14 + .../Styles/extra-components.scss | 1 + .../Components/BitComponentBase.cs | 2 +- .../BitMarkdownEditorDemo.razor | 21 ++ .../BitMarkdownEditorDemo.razor.cs | 22 ++ .../BitMarkdownEditorDemo.razor.scss | 7 + .../Pages/Home/ComponentsSection.razor | 3 + .../Shared/MainLayout.razor.NavItems.cs | 1 + .../compilerconfig.json | 6 + 13 files changed, 484 insertions(+), 1 deletion(-) create mode 100644 src/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownEditor/BitMarkdownEditor.razor create mode 100644 src/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownEditor/BitMarkdownEditor.razor.cs create mode 100644 src/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownEditor/BitMarkdownEditor.scss create mode 100644 src/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownEditor/BitMarkdownEditor.ts create mode 100644 src/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownEditor/BitMarkdownEditorJsRuntimeExtensions.cs create mode 100644 src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Extras/MarkdownEditor/BitMarkdownEditorDemo.razor create mode 100644 src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Extras/MarkdownEditor/BitMarkdownEditorDemo.razor.cs create mode 100644 src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Extras/MarkdownEditor/BitMarkdownEditorDemo.razor.scss diff --git a/src/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownEditor/BitMarkdownEditor.razor b/src/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownEditor/BitMarkdownEditor.razor new file mode 100644 index 0000000000..9d9802a461 --- /dev/null +++ b/src/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownEditor/BitMarkdownEditor.razor @@ -0,0 +1,11 @@ +@namespace Bit.BlazorUI +@inherits BitComponentBase + +<div @ref="RootElement" + @attributes="HtmlAttributes" + id="@_Id" + style="@StyleBuilder.Value" + class="@ClassBuilder.Value" + dir="@Dir?.ToString().ToLower()"> + <textarea @ref="_textAreaRef" class="bit-mde-txa" /> +</div> \ No newline at end of file diff --git a/src/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownEditor/BitMarkdownEditor.razor.cs b/src/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownEditor/BitMarkdownEditor.razor.cs new file mode 100644 index 0000000000..bd89745522 --- /dev/null +++ b/src/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownEditor/BitMarkdownEditor.razor.cs @@ -0,0 +1,34 @@ +namespace Bit.BlazorUI; + +/// <summary> +/// BitMarkdownEditor is a simple editor like GitHub md editor. +/// </summary> +public partial class BitMarkdownEditor : BitComponentBase +{ + private ElementReference _textAreaRef = default!; + + + + [Inject] private IJSRuntime _js { get; set; } = default!; + + + + public async ValueTask<string> GetValue() + { + return await _js.BitMarkdownEditorGetValue(_Id); + } + + + + protected override string RootElementClass => "bit-mde"; + + protected override Task OnAfterRenderAsync(bool firstRender) + { + if (firstRender) + { + _js.BitMarkdownEditorInit(_Id, _textAreaRef); + } + + return base.OnAfterRenderAsync(firstRender); + } +} diff --git a/src/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownEditor/BitMarkdownEditor.scss b/src/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownEditor/BitMarkdownEditor.scss new file mode 100644 index 0000000000..3220996f8b --- /dev/null +++ b/src/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownEditor/BitMarkdownEditor.scss @@ -0,0 +1,12 @@ +@import '../../../Bit.BlazorUI/Styles/functions.scss'; + +.bit-mde { + width: 100%; + box-sizing: border-box; +} + +.bit-mde-txa { + width: 100%; + height: 100%; + padding: spacing(1); +} diff --git a/src/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownEditor/BitMarkdownEditor.ts b/src/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownEditor/BitMarkdownEditor.ts new file mode 100644 index 0000000000..0e766c5a7d --- /dev/null +++ b/src/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownEditor/BitMarkdownEditor.ts @@ -0,0 +1,351 @@ +namespace BitBlazorUI { + type Content = { + value: string; + type: "inline" | "block" | "wrap"; + }; + + export class MarkdownEditor { + private static _editors: { [key: string]: MarkdownEditor } = {}; + + public static init(id: string, textArea: HTMLTextAreaElement) { + const editor = new MarkdownEditor(textArea); + + MarkdownEditor._editors[id] = editor; + } + + public static getValue(id: string) { + const editor = MarkdownEditor._editors[id]; + if (!editor) return; + + return editor.value; + } + + #opens: string[] = []; + + #pairs: { [key: string]: string } = { + "(": ")", + "{": "}", + "[": "]", + "<": ">", + '"': '"', + "`": "`", + }; + + #textArea: HTMLTextAreaElement; + + constructor(textArea: HTMLTextAreaElement) { + this.#textArea = textArea; + + this.#init(); + } + + get value() { + return this.#textArea.value; + } + + set value(value) { + this.#textArea.value = value; + } + + get #block() { + const codeBlocks = this.value.split("```"); + let total = 0; + for (const [i, b] of codeBlocks.entries()) { + total += b.length + 3; + if (this.#start < total) { + return i; + } + } + return 0; + } + + get #end() { + return this.#textArea.selectionEnd; + } + + get #start() { + return this.#textArea.selectionStart; + } + + #set(start: number, end: number) { + this.#textArea.setSelectionRange(start, end); + } + + #getLine() { + const total = this.value.split("\n"); + let count = 0; + for (let i = 0; i < total.length; i++) { + const length = total.at(i)?.length ?? 0; + count++; + count += length; + if (count > this.#end) { + return { + total, + num: i, + col: this.#end - (count - length - 1), + }; + } + } + return { total, num: 0, col: 0 }; + } + + #insert( + element: Content, + start: number, + end: number, + ) { + if (element.type === "inline") { + this.value = `${this.value.slice(0, end)}${element.value}${this.value.slice(end)}`; + } else if (element.type === "wrap") { + this.value = insert(this.value, element.value, start); + this.value = insert( + this.value, + this.#pairs[element.value] as string, + end + element.value.length, + ); + if (element.value.length < 2) this.#opens.push(element.value); + } else if (element.type === "block") { + const { total, num } = this.#getLine(); + const first = element.value.at(0); + if (first && total[num]?.startsWith(first)) { + total[num] = element.value.trim() + total[num]; + } else { + total[num] = element.value + total[num]; + } + this.value = total.join("\n"); + } + } + + #setCaret( + text: string, + start: number, + end: number, + ) { + let startPos = 0; + let endPos = 0; + if (/[a-z]/i.test(text)) { + for (let i = end; i < this.value.length; i++) { + if (this.value[i]?.match(/[a-z]/i)) { + if (!startPos) { + startPos = i; + } else { + endPos = i + 1; + } + } else if (startPos) { + break; + } + } + } else { + startPos = start + text.length; + endPos = end + text.length; + } + + this.#set(startPos, endPos); + this.#textArea.focus(); + } + + #add(element: Content) { + const end = this.#end; + const start = this.#start; + + this.#insert(element, start, end); + this.#setCaret(element.value, start, end); + } + + #getLists(str: string | undefined) { + if (!str) return; + + if (startsWithDash(str)) { + return '- '; + } + + const listNum = startsWithNumber(str); + if (listNum) return `${listNum}. `; + } + + #correct(cur: number, isDec = false) { + const { total } = this.#getLine(); + for (let i = cur + 1; i < total.length; i++) { + const l = total[i]; + if (!l) continue; + + if (startsWithDash(l)) { + if (l.length > 2) { + total[i] = l; + } else { + continue; + } + } else { + const number = startsWithNumber(l); + if (!number) { + break; + } else { + let newNumber: number; + if (isDec) { + if (number > 1) { + newNumber = number - 1; + } else { + break; + } + } else { + newNumber = number + 1; + } + total[i] = l.slice(String(number).length); + total[i] = String(newNumber) + total[i]; + } + } + } + this.value = total.join("\n"); + } + + #init() { + this.#textArea.addEventListener("keydown", async (e) => { + const reseters = ["Delete", "ArrowUp", "ArrowDown"]; + const next = this.value[this.#end] ?? ""; + if (reseters.includes(e.key)) { + this.#opens = []; + } else if (e.key === "Backspace") { + const prev = this.value[this.#start - 1]; + if ( + prev && + prev in this.#pairs && + next === this.#pairs[prev] + ) { + e.preventDefault(); + const start = this.#start - 1; + const end = this.#end - 1; + this.value = remove(this.value, start); + this.value = remove(this.value, end); + setTimeout(() => { + this.#set(start, end); + }, 0); + this.#opens.pop(); + } + if (prev === "\n" && this.#start === this.#end) { + e.preventDefault(); + const pos = this.#start - 1; + const { num } = this.#getLine(); + this.#correct(num, true); + this.value = remove(this.value, pos); + setTimeout(async () => { + this.#set(pos, pos); + }, 0); + } + } else if (e.key === "Tab") { + if (this.#block % 2 !== 0) { + e.preventDefault(); + this.#add({ + type: "inline", + value: "\t", + }); + } + } else if (e.key === "Enter") { + const { total, num, col } = this.#getLine(); + const line = total.at(num); + let rep = this.#getLists(line); + const orig = rep; + + const n = startsWithNumber(rep); + if (n) rep = `${n + 1}. `; + + if (rep && (orig && orig.length < col)) { + e.preventDefault(); + if (n) this.#correct(num); + this.#add({ + type: "inline", + value: `\n${rep}`, + }); + } else if (rep && (orig && orig.length === col)) { + e.preventDefault(); + + const origEnd = this.#end; + const pos = origEnd - orig.length; + + for (let i = 0; i < orig.length; i++) { + this.value = remove(this.value, origEnd - (i + 1)); + } + + setTimeout(async () => { + this.#set(pos, pos); + this.#textArea.focus(); + this.#add({ + type: "inline", + value: `\n`, + }); + }, 0); + } + } else { + const nextIsPaired = Object.values(this.#pairs).includes(next); + const isSelected = this.#start !== this.#end; + if (e.ctrlKey || e.metaKey) { + if (this.#start === this.#end) { + if (e.key === "c" || e.key === "x") { + e.preventDefault(); + const { total, num, col } = this.#getLine(); + + await navigator.clipboard.writeText(`${num === 0 && e.key === "x" ? "" : "\n"}${total[num]}`); + + if (e.key === "x") { + const pos = this.#start - col; + total.splice(num, 1); + this.value = total.join("\n"); + setTimeout(() => this.#set(pos, pos), 0); + } + } + } + } + + if ((e.ctrlKey || e.metaKey) && e.key) { + // TODO: handle shortkeys for example + } else if ( + nextIsPaired && + (next === e.key || e.key === "ArrowRight") && + this.#opens.length && + !isSelected + ) { + e.preventDefault(); + this.#set(this.#start + 1, this.#end + 1); + this.#opens.pop(); + } else if (e.key in this.#pairs) { + e.preventDefault(); + this.#add({ + type: "wrap", + value: e.key, + }); + this.#opens.push(e.key); + } + } + }); + + this.#textArea.addEventListener("dblclick", () => { + if (this.#start !== this.#end) { + if (this.value[this.#start] === " ") { + this.#set(this.#start + 1, this.#end); + } + if (this.value[this.#end - 1] === " ") { + this.#set(this.#start, this.#end - 1); + } + } + }); + + this.#textArea.addEventListener("click", () => (this.#opens = [])); + } + } + + const startsWithDash = (str: string | undefined) => { + return !!(str?.startsWith('- ')); + }; + + const startsWithNumber = (str: string | undefined) => { + const result = str?.match(/^(\d+)\./); + return result ? Number(result[1]) : null; + }; + + const insert = (str: string, char: string, index: number) => { + return str.slice(0, index) + char + str.slice(index); + }; + + const remove = (str: string, index: number) => { + return str.slice(0, index) + str.slice(index + 1); + }; +} \ No newline at end of file diff --git a/src/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownEditor/BitMarkdownEditorJsRuntimeExtensions.cs b/src/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownEditor/BitMarkdownEditorJsRuntimeExtensions.cs new file mode 100644 index 0000000000..795bce58c9 --- /dev/null +++ b/src/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownEditor/BitMarkdownEditorJsRuntimeExtensions.cs @@ -0,0 +1,14 @@ +namespace Bit.BlazorUI; + +internal static class BitMarkdownEditorJsRuntimeExtensions +{ + public static ValueTask BitMarkdownEditorInit(this IJSRuntime jsRuntime, string id, ElementReference element) + { + return jsRuntime.InvokeVoid("BitBlazorUI.MarkdownEditor.init", id, element); + } + + public static ValueTask<string> BitMarkdownEditorGetValue(this IJSRuntime jsRuntime, string id) + { + return jsRuntime.Invoke<string>("BitBlazorUI.MarkdownEditor.getValue", id); + } +} diff --git a/src/BlazorUI/Bit.BlazorUI.Extras/Styles/extra-components.scss b/src/BlazorUI/Bit.BlazorUI.Extras/Styles/extra-components.scss index a58e1aa4f7..a5be6a9d53 100644 --- a/src/BlazorUI/Bit.BlazorUI.Extras/Styles/extra-components.scss +++ b/src/BlazorUI/Bit.BlazorUI.Extras/Styles/extra-components.scss @@ -3,6 +3,7 @@ @import "../Components/DataGrid/Pagination/BitDataGridPaginator.scss"; @import "../Components/ErrorBoundary/BitErrorBoundary.scss"; @import "../Components/InfiniteScrolling/BitInfiniteScrolling.scss"; +@import "../Components/MarkdownEditor/BitMarkdownEditor.scss"; @import "../Components/MarkdownViewer/BitMarkdownViewer.scss"; @import "../Components/MessageBox/BitMessageBox.scss"; @import "../Components/NavPanel/BitNavPanel.scss"; diff --git a/src/BlazorUI/Bit.BlazorUI/Components/BitComponentBase.cs b/src/BlazorUI/Bit.BlazorUI/Components/BitComponentBase.cs index 3f496563bf..eea0bb5368 100644 --- a/src/BlazorUI/Bit.BlazorUI/Components/BitComponentBase.cs +++ b/src/BlazorUI/Bit.BlazorUI/Components/BitComponentBase.cs @@ -78,7 +78,7 @@ public BitDir? Dir public override Task SetParametersAsync(ParameterView parameters) { HtmlAttributes.Clear(); - var parametersDictionary = ParametersCache ?? throw new InvalidOperationException(); + var parametersDictionary = ParametersCache ?? new Dictionary<string, object?>(parameters.ToDictionary()); foreach (var parameter in parametersDictionary!) { switch (parameter.Key) diff --git a/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Extras/MarkdownEditor/BitMarkdownEditorDemo.razor b/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Extras/MarkdownEditor/BitMarkdownEditorDemo.razor new file mode 100644 index 0000000000..010ddd47a0 --- /dev/null +++ b/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Extras/MarkdownEditor/BitMarkdownEditorDemo.razor @@ -0,0 +1,21 @@ +@page "/components/markdowneditor" + +<PageOutlet Url="components/markdowneditor" + Title="MarkdownEditor" + Description="markdowneditor component of the bit BlazorUI components" /> + +<DemoPage Name="MarkdownEditor" + Notes="To use this component, you need to install the `Bit.BlazorUI.Extras` nuget package, as described in the Optional steps of the Getting started page." + Description="BitMarkdownEditor is a SEO friendly Blazor wrapper around the famous markedjs library." + SecondaryNames="@(["MdViewer", "MD"])" + Parameters="componentParameters"> + <DemoSection Title="Basic" RazorCode="@example1RazorCode" Id="example1"> + <BitButton OnClick="GetValue">Get Value</BitButton> + <div style="margin-top:1rem;display:flex;flex-direction:row;gap:1rem;height:300px"> + <BitMarkdownEditor @ref="editorRef" /> + <pre style="width:100%"> + @value + </pre> + </div> + </DemoSection> +</DemoPage> diff --git a/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Extras/MarkdownEditor/BitMarkdownEditorDemo.razor.cs b/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Extras/MarkdownEditor/BitMarkdownEditorDemo.razor.cs new file mode 100644 index 0000000000..50c68a6101 --- /dev/null +++ b/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Extras/MarkdownEditor/BitMarkdownEditorDemo.razor.cs @@ -0,0 +1,22 @@ +namespace Bit.BlazorUI.Demo.Client.Core.Pages.Components.Extras.MarkdownEditor; + +public partial class BitMarkdownEditorDemo +{ + private readonly List<ComponentParameter> componentParameters = + [ + ]; + + + + private BitMarkdownEditor editorRef = default!; + private string? value; + private async Task GetValue() + { + value = await editorRef.GetValue(); + } + + + + private readonly string example1RazorCode = @" +<BitMarkdownViewer Markdown=""@(""# Marked in the browser\n\nRendered by **marked**."")"" />"; +} diff --git a/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Extras/MarkdownEditor/BitMarkdownEditorDemo.razor.scss b/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Extras/MarkdownEditor/BitMarkdownEditorDemo.razor.scss new file mode 100644 index 0000000000..954a678855 --- /dev/null +++ b/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Extras/MarkdownEditor/BitMarkdownEditorDemo.razor.scss @@ -0,0 +1,7 @@ +::deep { + .advanced { + img { + max-width: 100%; + } + } +} diff --git a/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Home/ComponentsSection.razor b/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Home/ComponentsSection.razor index d496fabc78..f78a206150 100644 --- a/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Home/ComponentsSection.razor +++ b/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Home/ComponentsSection.razor @@ -259,6 +259,9 @@ <BitLink Href="/components/infinitescrolling" title="InfiniteScrolling" Style="display: flex"> <BitText Typography="BitTypography.Subtitle1">InfiniteScrolling</BitText> </BitLink> + <BitLink Href="/components/markdowneditor" title="MarkdownEditor" Style="display: flex"> + <BitText Typography="BitTypography.Subtitle1">MarkdownEditor</BitText> + </BitLink> <BitLink Href="/components/markdownviewer" title="MarkdownViewer" Style="display: flex"> <BitText Typography="BitTypography.Subtitle1">MarkdownViewer</BitText> </BitLink> diff --git a/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Shared/MainLayout.razor.NavItems.cs b/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Shared/MainLayout.razor.NavItems.cs index 0df3a24cac..4e03ceb45a 100644 --- a/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Shared/MainLayout.razor.NavItems.cs +++ b/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Shared/MainLayout.razor.NavItems.cs @@ -155,6 +155,7 @@ public partial class MainLayout new() { Text = "DataGrid", Url = "/components/datagrid", AdditionalUrls = ["/components/data-grid"] }, new() { Text = "ErrorBoundary", Url = "/components/errorboundary" }, new() { Text = "InfiniteScrolling", Url = "/components/infinitescrolling" }, + new() { Text = "MarkdownEditor", Url = "/components/markdowneditor", Description = "MdEditor" }, new() { Text = "MarkdownViewer", Url = "/components/markdownviewer", Description = "MdViewer, MD" }, new() { Text = "MessageBox", Url = "/components/messagebox" }, new() { Text = "NavPanel", Url = "/components/navpanel" }, diff --git a/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/compilerconfig.json b/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/compilerconfig.json index 67619b86d9..b6e9834124 100644 --- a/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/compilerconfig.json +++ b/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/compilerconfig.json @@ -77,6 +77,12 @@ "minify": { "enabled": false }, "options": { "sourceMap": false } }, + { + "outputFile": "Pages/Components/Extras/MarkdownEditor/BitMarkdownEditorDemo.razor.css", + "inputFile": "Pages/Components/Extras/MarkdownEditor/BitMarkdownEditorDemo.razor.scss", + "minify": { "enabled": false }, + "options": { "sourceMap": false } + }, { "outputFile": "Pages/Components/Extras/MarkdownViewer/BitMarkdownViewerDemo.razor.css", "inputFile": "Pages/Components/Extras/MarkdownViewer/BitMarkdownViewerDemo.razor.scss", From b3a11034f4d96fa13429b849f856c432e214bde9 Mon Sep 17 00:00:00 2001 From: Saleh Yusefnejad <msynk@outlook.com> Date: Mon, 17 Mar 2025 17:04:02 +0330 Subject: [PATCH 2/2] fix review --- .../MarkdownEditor/BitMarkdownEditor.razor.cs | 3 +++ .../MarkdownEditor/BitMarkdownEditorDemo.razor | 2 +- .../MarkdownEditor/BitMarkdownEditorDemo.razor.cs | 15 ++++++++++++++- .../BitMarkdownEditorDemo.razor.scss | 5 ----- 4 files changed, 18 insertions(+), 7 deletions(-) diff --git a/src/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownEditor/BitMarkdownEditor.razor.cs b/src/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownEditor/BitMarkdownEditor.razor.cs index bd89745522..bff1b45cbb 100644 --- a/src/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownEditor/BitMarkdownEditor.razor.cs +++ b/src/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownEditor/BitMarkdownEditor.razor.cs @@ -13,6 +13,9 @@ public partial class BitMarkdownEditor : BitComponentBase + /// <summary> + /// Returns the current value of the editor. + /// </summary> public async ValueTask<string> GetValue() { return await _js.BitMarkdownEditorGetValue(_Id); diff --git a/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Extras/MarkdownEditor/BitMarkdownEditorDemo.razor b/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Extras/MarkdownEditor/BitMarkdownEditorDemo.razor index 010ddd47a0..98ce765a56 100644 --- a/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Extras/MarkdownEditor/BitMarkdownEditorDemo.razor +++ b/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Extras/MarkdownEditor/BitMarkdownEditorDemo.razor @@ -9,7 +9,7 @@ Description="BitMarkdownEditor is a SEO friendly Blazor wrapper around the famous markedjs library." SecondaryNames="@(["MdViewer", "MD"])" Parameters="componentParameters"> - <DemoSection Title="Basic" RazorCode="@example1RazorCode" Id="example1"> + <DemoSection Title="Basic" RazorCode="@example1RazorCode" CsharpCode="@example1CsharpCode" Id="example1"> <BitButton OnClick="GetValue">Get Value</BitButton> <div style="margin-top:1rem;display:flex;flex-direction:row;gap:1rem;height:300px"> <BitMarkdownEditor @ref="editorRef" /> diff --git a/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Extras/MarkdownEditor/BitMarkdownEditorDemo.razor.cs b/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Extras/MarkdownEditor/BitMarkdownEditorDemo.razor.cs index 50c68a6101..743aa373b8 100644 --- a/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Extras/MarkdownEditor/BitMarkdownEditorDemo.razor.cs +++ b/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Extras/MarkdownEditor/BitMarkdownEditorDemo.razor.cs @@ -18,5 +18,18 @@ private async Task GetValue() private readonly string example1RazorCode = @" -<BitMarkdownViewer Markdown=""@(""# Marked in the browser\n\nRendered by **marked**."")"" />"; +<BitButton OnClick=""GetValue"">Get Value</BitButton> +<div style=""margin-top:1rem;display:flex;flex-direction:row;gap:1rem;height:300px""> + <BitMarkdownEditor @ref=""editorRef"" /> + <pre style=""width:100%""> + @value + </pre> +</div>"; + private readonly string example1CsharpCode = @" +private BitMarkdownEditor editorRef = default!; +private string? value; +private async Task GetValue() +{ + value = await editorRef.GetValue(); +}"; } diff --git a/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Extras/MarkdownEditor/BitMarkdownEditorDemo.razor.scss b/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Extras/MarkdownEditor/BitMarkdownEditorDemo.razor.scss index 954a678855..e4c5a61f90 100644 --- a/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Extras/MarkdownEditor/BitMarkdownEditorDemo.razor.scss +++ b/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Extras/MarkdownEditor/BitMarkdownEditorDemo.razor.scss @@ -1,7 +1,2 @@ ::deep { - .advanced { - img { - max-width: 100%; - } - } }