diff --git a/src/SufiChain.SufiBlazor/Components/Forms/SbMarkEditor.razor b/src/SufiChain.SufiBlazor/Components/Forms/SbMarkEditor.razor
new file mode 100644
index 0000000..0a23721
--- /dev/null
+++ b/src/SufiChain.SufiBlazor/Components/Forms/SbMarkEditor.razor
@@ -0,0 +1,34 @@
+@namespace SufiChain.SufiBlazor.Components.Forms
+@using SufiChain.SufiBlazor.Contracts.Editors
+
+
diff --git a/src/SufiChain.SufiBlazor/Components/Forms/SbMarkEditor.razor.cs b/src/SufiChain.SufiBlazor/Components/Forms/SbMarkEditor.razor.cs
new file mode 100644
index 0000000..f482686
--- /dev/null
+++ b/src/SufiChain.SufiBlazor/Components/Forms/SbMarkEditor.razor.cs
@@ -0,0 +1,65 @@
+using Microsoft.AspNetCore.Components;
+using SufiChain.SufiBlazor.Contracts.Editors;
+
+namespace SufiChain.SufiBlazor.Components.Forms;
+
+public partial class SbMarkEditor
+{
+ [Parameter] public string Value { get; set; } = string.Empty;
+ [Parameter] public EventCallback ValueChanged { get; set; }
+ [Parameter] public string? ValueHtml { get; set; }
+ [Parameter] public EventCallback ValueHtmlChanged { get; set; }
+ [Parameter] public bool ReadOnly { get; set; }
+ [Parameter] public bool Disabled { get; set; }
+ [Parameter] public string? Placeholder { get; set; }
+ [Parameter] public string? Class { get; set; }
+ [Parameter] public string? Style { get; set; }
+ [Parameter] public bool RightToLeft { get; set; }
+ [Parameter] public bool EnablePreview { get; set; } = true;
+ [Parameter] public bool EnableMermaid { get; set; } = true;
+ [Parameter] public bool EnableHighlight { get; set; } = true;
+ [Parameter] public string HighlightTheme { get; set; } = "github";
+ [Parameter] public SbMarkEditorMode Mode { get; set; } = SbMarkEditorMode.Markdown;
+ [Parameter] public string? SourceLanguage { get; set; }
+ [Parameter] public bool UseToolbarContributors { get; set; }
+ [Parameter] public bool IncludeDefaultToolbarItems { get; set; } = true;
+ [Parameter] public bool HideToolbar { get; set; }
+ [Parameter] public IReadOnlyList? ToolbarItems { get; set; }
+ [Parameter] public EventCallback OnShortcut { get; set; }
+ [Parameter] public string? MinHeight { get; set; } = "200px";
+ [Parameter] public string? MaxHeight { get; set; }
+ [Parameter] public int FallbackRows { get; set; } = 12;
+ [Parameter] public bool IsDiffReview { get; set; }
+ [Parameter] public string OriginalValue { get; set; } = string.Empty;
+ [Parameter] public string SuggestedValue { get; set; } = string.Empty;
+ [Parameter] public EventCallback SuggestedValueChanged { get; set; }
+ [Parameter] public EventCallback OnApplyChanges { get; set; }
+ [Parameter] public EventCallback OnDiscardChanges { get; set; }
+ [Parameter(CaptureUnmatchedValues = true)]
+ public Dictionary? AdditionalAttributes { get; set; }
+
+ private SbMarkdownEditorMode ResolveEditorMode()
+ {
+ return Mode switch
+ {
+ SbMarkEditorMode.Source => SbMarkdownEditorMode.Source,
+ SbMarkEditorMode.Markup => SbMarkdownEditorMode.Source,
+ _ => SbMarkdownEditorMode.Markdown
+ };
+ }
+
+ private string? ResolveSourceLanguage()
+ {
+ if (!string.IsNullOrWhiteSpace(SourceLanguage))
+ {
+ return SourceLanguage;
+ }
+
+ return Mode switch
+ {
+ SbMarkEditorMode.Markup => "html",
+ SbMarkEditorMode.Source => "html",
+ _ => null
+ };
+ }
+}
diff --git a/src/SufiChain.SufiBlazor/Contracts/Editors/SbMarkEditorMode.cs b/src/SufiChain.SufiBlazor/Contracts/Editors/SbMarkEditorMode.cs
new file mode 100644
index 0000000..f08b60c
--- /dev/null
+++ b/src/SufiChain.SufiBlazor/Contracts/Editors/SbMarkEditorMode.cs
@@ -0,0 +1,8 @@
+namespace SufiChain.SufiBlazor.Contracts.Editors;
+
+public enum SbMarkEditorMode
+{
+ Markdown,
+ Markup,
+ Source
+}
diff --git a/src/SufiChain.SufiBlazor/wwwroot/sufiblazor-markdown-editor.js b/src/SufiChain.SufiBlazor/wwwroot/sufiblazor-markdown-editor.js
index b4a7465..ad47dff 100644
--- a/src/SufiChain.SufiBlazor/wwwroot/sufiblazor-markdown-editor.js
+++ b/src/SufiChain.SufiBlazor/wwwroot/sufiblazor-markdown-editor.js
@@ -323,6 +323,7 @@ export async function initEditor(textarea, dotNetRef, options) {
easyOptions.preview = false;
easyOptions.sideBySideFullscreen = false;
} else {
+ easyOptions.sideBySideFullscreen = false;
easyOptions.previewRender = buildPreviewRender(options);
easyOptions.renderingConfig.markedOptions = {
highlight: buildHighlightFn(options.enableHighlight, options.enableMermaid)
@@ -435,6 +436,20 @@ export function insertTextAtCursor(editorId, text) {
cm.focus();
}
+function toggleContainerFullscreen(stored) {
+ const wrapper = stored.easyMDE.codemirror.getWrapperElement();
+ const container = wrapper?.closest('.sb-markdown-editor');
+ if (!container) {
+ return;
+ }
+
+ container.classList.toggle('sb-markdown-editor--fullscreen');
+ document.documentElement.classList.toggle(
+ 'sb-markdown-editor-fullscreen-active',
+ container.classList.contains('sb-markdown-editor--fullscreen'));
+ stored.easyMDE.codemirror.refresh();
+}
+
export function execAction(editorId, action, value) {
const stored = editors.get(editorId);
if (!stored) {
@@ -457,7 +472,7 @@ export function execAction(editorId, action, value) {
case 'image': easyMDE.drawImage(); break;
case 'preview': easyMDE.togglePreview(); break;
case 'side-by-side': easyMDE.toggleSideBySide(); break;
- case 'fullscreen': easyMDE.toggleFullScreen(); break;
+ case 'fullscreen': toggleContainerFullscreen(stored); break;
case 'undo': easyMDE.codemirror.undo(); break;
case 'redo': easyMDE.codemirror.redo(); break;
default:
diff --git a/src/SufiChain.SufiBlazor/wwwroot/sufiblazor.css b/src/SufiChain.SufiBlazor/wwwroot/sufiblazor.css
index 055e993..84f6c2b 100644
--- a/src/SufiChain.SufiBlazor/wwwroot/sufiblazor.css
+++ b/src/SufiChain.SufiBlazor/wwwroot/sufiblazor.css
@@ -8445,6 +8445,55 @@ body.sb-resizing {
color: var(--sb-color-text);
}
+.sb-markdown-editor .EasyMDEContainer.sided--no-fullscreen {
+ display: flex;
+ flex-wrap: wrap;
+ width: 100%;
+}
+
+.sb-markdown-editor .EasyMDEContainer.sided--no-fullscreen .CodeMirror-sided,
+.sb-markdown-editor .EasyMDEContainer.sided--no-fullscreen .editor-preview-side {
+ flex: 1 1 50%;
+ width: 50% !important;
+ min-width: 20rem;
+ position: static !important;
+ inset: auto !important;
+ height: auto;
+ max-height: none;
+}
+
+.sb-markdown-editor .EasyMDEContainer.sided--no-fullscreen .editor-preview-active-side {
+ display: block;
+}
+
+.sb-markdown-editor-fullscreen-active,
+.sb-markdown-editor-fullscreen-active body {
+ overflow: hidden;
+}
+
+.sb-markdown-editor.sb-markdown-editor--fullscreen {
+ position: fixed;
+ inset: var(--sb-space-4);
+ z-index: 2000;
+ min-height: auto;
+ background: var(--sb-color-surface);
+ box-shadow: var(--sb-shadow-xl, 0 24px 64px rgba(15, 23, 42, 0.22));
+}
+
+.sb-markdown-editor.sb-markdown-editor--fullscreen .EasyMDEContainer {
+ flex: 1 1 auto;
+ min-height: 0;
+}
+
+.sb-markdown-editor.sb-markdown-editor--fullscreen .EasyMDEContainer .CodeMirror {
+ height: calc(100vh - 9rem) !important;
+}
+
+.sb-markdown-editor.sb-markdown-editor--fullscreen .EasyMDEContainer.sided--no-fullscreen .CodeMirror-sided,
+.sb-markdown-editor.sb-markdown-editor--fullscreen .EasyMDEContainer.sided--no-fullscreen .editor-preview-side {
+ height: calc(100vh - 9rem) !important;
+}
+
.sb-markdown-viewer pre,
.sb-markdown-viewer code {
font-family: var(--sb-font-family-mono, monospace);