diff --git a/CodeMirror6/CodeMirror6Wrapper.razor b/CodeMirror6/CodeMirror6Wrapper.razor index e78f2137..a00ce1be 100644 --- a/CodeMirror6/CodeMirror6Wrapper.razor +++ b/CodeMirror6/CodeMirror6Wrapper.razor @@ -1,8 +1,8 @@ -@if (ContentBefore is not null && CmJsInterop is not null && Config is not null && Commands is not null) { - @ContentBefore((Commands, Config, State)) -} - + + @if (ContentBefore is not null && CmJsInterop is not null && Config is not null && CommandDispatcher is not null) { + @ContentBefore((CommandDispatcher, Config, State)) + }
+ @if (ContentAfter is not null && CmJsInterop is not null && Config is not null && CommandDispatcher is not null) { + @ContentAfter((CommandDispatcher, Config, State)) + }
- -@if (ContentAfter is not null && CmJsInterop is not null && Config is not null && Commands is not null) { - @ContentAfter((Commands, Config, State)) -} diff --git a/CodeMirror6/CodeMirror6Wrapper.razor.JsInterop.cs b/CodeMirror6/CodeMirror6Wrapper.razor.JsInterop.cs index 99c86c09..8087e324 100644 --- a/CodeMirror6/CodeMirror6Wrapper.razor.JsInterop.cs +++ b/CodeMirror6/CodeMirror6Wrapper.razor.JsInterop.cs @@ -68,7 +68,7 @@ internal async Task ModuleInvokeVoidAsync(string method, params object?[] args) /// Methods to invoke JS CodeMirror commands. /// /// - internal CMCommandDispatcher Commands => _commands ??= new(this); + internal CMCommandDispatcher CommandDispatcher => _commands ??= new(this); /// /// Dispose Javascript modules diff --git a/CodeMirror6/CodeMirror6Wrapper.razor.cs b/CodeMirror6/CodeMirror6Wrapper.razor.cs index f161fa44..b8dd91d1 100644 --- a/CodeMirror6/CodeMirror6Wrapper.razor.cs +++ b/CodeMirror6/CodeMirror6Wrapper.razor.cs @@ -75,6 +75,11 @@ public partial class CodeMirror6Wrapper : ComponentBase, IAsyncDisposable /// [Parameter] public bool Editable { get; set; } = true; /// + /// Controls whether long lines should wrap + /// + /// + [Parameter] public bool LineWrapping { get; set; } = true; + /// /// The language to use in the editor /// /// @@ -148,7 +153,7 @@ public partial class CodeMirror6Wrapper : ComponentBase, IAsyncDisposable /// Methods to invoke JS CodeMirror commands. /// /// - public CMCommandDispatcher? Commands => CmJsInterop?.Commands; + public CMCommandDispatcher? CommandDispatcher => CmJsInterop?.CommandDispatcher; private string LoadingDivId => $"{Id}_Loading"; private string ResizeStyle => AllowVerticalResize && AllowHorizontalResize @@ -180,7 +185,8 @@ protected override async Task OnInitializedAsync() Language?.ToString(), AutoFormatMarkdown, ReplaceEmojiCodes, - ResizeStyle + ResizeStyle, + LineWrapping ); try { await OnAfterRenderAsync(true); // try early initialization for Blazor WASM @@ -262,6 +268,10 @@ protected override async Task OnParametersSetAsync() Config.Resize = ResizeStyle; await CmJsInterop.PropertySetters.SetResize(); } + if (Config.LineWrapping != LineWrapping) { + Config.LineWrapping = LineWrapping; + await CmJsInterop.PropertySetters.SetLineWrapping(); + } shouldRender = true; } diff --git a/CodeMirror6/CodeMirror6Wrapper.razor.css b/CodeMirror6/CodeMirror6Wrapper.razor.css index 9f92be46..e4434a73 100644 --- a/CodeMirror6/CodeMirror6Wrapper.razor.css +++ b/CodeMirror6/CodeMirror6Wrapper.razor.css @@ -7,6 +7,7 @@ ::deep .cm-editor { overflow: auto; max-height: inherit; + max-width: 100%; } ::deep .resize-none .cm-editor { diff --git a/CodeMirror6/Commands/CMCommandDispatcher.cs b/CodeMirror6/Commands/CMCommandDispatcher.cs index 8b4140e2..71834447 100644 --- a/CodeMirror6/Commands/CMCommandDispatcher.cs +++ b/CodeMirror6/Commands/CMCommandDispatcher.cs @@ -1,5 +1,3 @@ -using CodeMirror6.Commands; - namespace CodeMirror6.Models; /// diff --git a/CodeMirror6/Commands/CMConfigurationSetters.cs b/CodeMirror6/Commands/CMConfigurationSetters.cs index ef2c1d95..dc16d92a 100644 --- a/CodeMirror6/Commands/CMConfigurationSetters.cs +++ b/CodeMirror6/Commands/CMConfigurationSetters.cs @@ -122,4 +122,9 @@ internal Task SetResize() => cmJsInterop.ModuleInvokeVoidAsync( "setResize", config.Resize ); + + internal Task SetLineWrapping() => cmJsInterop.ModuleInvokeVoidAsync( + "setLineWrapping", + config.LineWrapping + ); } diff --git a/CodeMirror6/Models/CodeMirrorConfiguration.cs b/CodeMirror6/Models/CodeMirrorConfiguration.cs index d0dfb05a..3c71f555 100644 --- a/CodeMirror6/Models/CodeMirrorConfiguration.cs +++ b/CodeMirror6/Models/CodeMirrorConfiguration.cs @@ -17,6 +17,7 @@ namespace CodeMirror6.Models; /// /// /// none, vertical, horizontal or both +/// public class CodeMirrorConfiguration( string? doc, string? placeholder, @@ -28,7 +29,8 @@ public class CodeMirrorConfiguration( string? languageName, bool autoFormatMarkdown, bool replaceEmojiCodes, - string resize) + string resize, + bool lineWrapping) { /// @@ -86,4 +88,9 @@ public class CodeMirrorConfiguration( /// Controls whether the editor should have a resize handle like a textarea /// [JsonPropertyName("resize")] public string Resize { get; internal set; } = resize; + + /// + /// Controls whether the editor wraps long lines of text, versus using scroll-bars + /// + [JsonPropertyName("lineWrapping")] public bool LineWrapping { get; internal set; } = lineWrapping; } diff --git a/CodeMirror6/NodeLib/src/CmConfiguration.ts b/CodeMirror6/NodeLib/src/CmConfiguration.ts index 44dfac51..f54f528f 100644 --- a/CodeMirror6/NodeLib/src/CmConfiguration.ts +++ b/CodeMirror6/NodeLib/src/CmConfiguration.ts @@ -13,4 +13,5 @@ export class CmConfiguration { public autoFormatMarkdown: boolean public replaceEmojiCodes: boolean public resize: string + public lineWrapping: boolean } diff --git a/CodeMirror6/NodeLib/src/CmInstance.ts b/CodeMirror6/NodeLib/src/CmInstance.ts index a41a0909..bc1a2376 100644 --- a/CodeMirror6/NodeLib/src/CmInstance.ts +++ b/CodeMirror6/NodeLib/src/CmInstance.ts @@ -22,6 +22,7 @@ export class CmInstance public editableCompartment: Compartment = new Compartment public keymapCompartment: Compartment = new Compartment public emojiReplacerCompartment: Compartment = new Compartment + public lineWrappingCompartment: Compartment = new Compartment } export const CMInstances: { [id: string]: CmInstance} = {} diff --git a/CodeMirror6/NodeLib/src/index.ts b/CodeMirror6/NodeLib/src/index.ts index ea948cf1..4dfbcbc1 100644 --- a/CodeMirror6/NodeLib/src/index.ts +++ b/CodeMirror6/NodeLib/src/index.ts @@ -97,6 +97,7 @@ export async function initCodeMirror( CMInstances[id].emojiReplacerCompartment.of(replaceEmojiExtension(initialConfig.replaceEmojiCodes)), lastOperationWasUndo, indentationMarkers(), + CMInstances[id].lineWrappingCompartment.of(initialConfig.lineWrapping ? EditorView.lineWrapping : []), EditorView.updateListener.of(async (update) => { await updateListenerExtension(dotnetHelper, update) }), keymap.of([ @@ -264,6 +265,12 @@ export function setEditable(id: string, editable: boolean) { }) } +export function setLineWrapping(id: string, lineWrapping: boolean) { + CMInstances[id].view.dispatch({ + effects: CMInstances[id].lineWrappingCompartment.reconfigure(lineWrapping ? EditorView.lineWrapping : []) + }) +} + export function setLanguage(id: string, languageName: string) { const language = getLanguage(languageName) const customKeyMap = getLanguageKeyMaps(languageName) diff --git a/Examples.BlazorServer/Shared/MainLayout.razor.css b/Examples.BlazorServer/Shared/MainLayout.razor.css index 699f17cd..f02fb9d5 100644 --- a/Examples.BlazorServer/Shared/MainLayout.razor.css +++ b/Examples.BlazorServer/Shared/MainLayout.razor.css @@ -2,10 +2,13 @@ position: relative; display: flex; flex-direction: column; + overflow-y: auto; + overflow-x: hidden; } main { flex: 1; + width: 100vw; } .sidebar { @@ -21,15 +24,16 @@ main { align-items: center; } - .top-row ::deep a, .top-row .btn-link { - white-space: nowrap; - margin-left: 1.5rem; - } +.top-row ::deep a, +.top-row .btn-link { + white-space: nowrap; + margin-left: 1.5rem; +} - .top-row a:first-child { - overflow: hidden; - text-overflow: ellipsis; - } +.top-row a:first-child { + overflow: hidden; + text-overflow: ellipsis; +} @media (max-width: 640.98px) { .top-row:not(.auth) { @@ -40,7 +44,8 @@ main { justify-content: space-between; } - .top-row a, .top-row .btn-link { + .top-row a, + .top-row .btn-link { margin-left: 0; } } @@ -63,8 +68,9 @@ main { z-index: 1; } - .top-row, article { + /* .top-row, + article { padding-left: 2rem !important; padding-right: 1.5rem !important; - } + } */ } diff --git a/Examples.BlazorWasm/Shared/MainLayout.razor.css b/Examples.BlazorWasm/Shared/MainLayout.razor.css index c7ac7630..f1ef6235 100644 --- a/Examples.BlazorWasm/Shared/MainLayout.razor.css +++ b/Examples.BlazorWasm/Shared/MainLayout.razor.css @@ -2,10 +2,13 @@ position: relative; display: flex; flex-direction: column; + overflow-y: auto; + overflow-x: hidden; } main { flex: 1; + width: 100vw; } .sidebar { @@ -21,20 +24,22 @@ main { align-items: center; } - .top-row ::deep a, .top-row ::deep .btn-link { - white-space: nowrap; - margin-left: 1.5rem; - text-decoration: none; - } +.top-row ::deep a, +.top-row ::deep .btn-link { + white-space: nowrap; + margin-left: 1.5rem; + text-decoration: none; +} - .top-row ::deep a:hover, .top-row ::deep .btn-link:hover { - text-decoration: underline; - } +.top-row ::deep a:hover, +.top-row ::deep .btn-link:hover { + text-decoration: underline; +} - .top-row ::deep a:first-child { - overflow: hidden; - text-overflow: ellipsis; - } +.top-row ::deep a:first-child { + overflow: hidden; + text-overflow: ellipsis; +} @media (max-width: 640.98px) { .top-row:not(.auth) { @@ -45,15 +50,16 @@ main { justify-content: space-between; } - .top-row ::deep a, .top-row ::deep .btn-link { + .top-row ::deep a, + .top-row ::deep .btn-link { margin-left: 0; } } @media (min-width: 641px) { - .page { + /* .page { flex-direction: row; - } + } */ .sidebar { width: 250px; @@ -74,8 +80,9 @@ main { width: 0; } - .top-row, article { + /* .top-row, + article { padding-left: 2rem !important; padding-right: 1.5rem !important; - } + } */ } diff --git a/Examples.Common/Example.razor b/Examples.Common/Example.razor index 475799a9..179f135e 100644 --- a/Examples.Common/Example.razor +++ b/Examples.Common/Example.razor @@ -33,6 +33,7 @@ @bind-Doc=@Text Placeholder="Enter your code.... (1)" TabSize=@TabSize + IndentationUnit=@TabSize @bind-Selection=@selectionRanges1 Theme=@Theme Language=@Language @@ -42,6 +43,9 @@ ReplaceEmojiCodes=@ReplaceEmojiCodes GetMentionCompletions=@GetMentionCompletions UploadFile=@UploadFile + Editable + ReadOnly=false + LineWrapping=@LineWrapping style="max-width: 100%; max-height: 60em; " > @@ -94,6 +98,9 @@ + @@ -196,6 +203,7 @@ Result: private CodeMirrorLanguage Language = CodeMirrorLanguage.Markdown; private bool AutoFormatMarkdown = true; private bool ReplaceEmojiCodes = false; + private bool LineWrapping = true; private readonly CodeMirrorSetup Setup = new() { HighlightActiveLine = false, LineNumbers = true, diff --git a/Examples.Common/Example.razor.Markdown.cs b/Examples.Common/Example.razor.Markdown.cs index 1211d205..a864979b 100644 --- a/Examples.Common/Example.razor.Markdown.cs +++ b/Examples.Common/Example.razor.Markdown.cs @@ -27,6 +27,8 @@ @abc @def @fff Bats with red teeth and blue eyes ! +Long line, Long line, Long line, Long line, Long line, Long line, Long line, Long line, Long line, Long line, Long line, Long line, Long line, Long line, Long line, Long line, Long line, Long line, Long line, Long line, Long line, Long line, Long line, Long line, Long line, Long line, Long line, Long line, Long line, Long line, Long line, Long line + --- - [ ] task 1 diff --git a/README.md b/README.md index 792ccc11..dc7c3d94 100644 --- a/README.md +++ b/README.md @@ -29,8 +29,8 @@ Blazor CodeMirror 6 brings the power of the [CodeMirror 6](https://codemirror.ne - [x] allow undo / redo toolbar buttons - [x] configure which plugins are active at startup - [x] optionally scroll to the bottom of the document & place the cursor on the last line +- [x] support long line wrapping - [ ] toolbar with toolbar button template -- [ ] support soft line wrapping - [ ] support read-only paragraphs - [ ] diff viewer - [ ] Implement cursor tooltips