Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improve BitMarkdownEditor (#10271) #10272

Merged

Conversation

msynk
Copy link
Member

@msynk msynk commented Mar 18, 2025

closes #10271

Summary by CodeRabbit

  • New Features

    • Enhanced the Markdown editor with new parameters for setting an initial text value, handling text changes via callbacks, and enabling two-way data binding.
    • Improved initialization and event handling for a smoother editing experience, including enhanced interactivity and cleanup.
  • Style

    • Adjusted the editor’s styling to fully utilize its container’s height.
  • Demo Enhancements

    • Updated demo pages to showcase the new editor configurations and usage scenarios.

Copy link

coderabbitai bot commented Mar 18, 2025

Walkthrough

The changes enhance the functionality of the Markdown editor component by introducing new public parameters for input binding (Value, DefaultValue, OnChange) and a new JS-invocable method for handling change events. The component’s lifecycle management is improved with updates to initialization (via JS interop) and disposal logic. In addition, the TypeScript side now accepts extra parameters with refined event and key handling logic, and the CSS has been updated to ensure full height usage. Demo pages have been augmented with new examples demonstrating the enhanced features.

Changes

File(s) Change Summary
src/BlazorUI/.../MarkdownEditor/BitMarkdownEditor.razor.cs Added public parameters (DefaultValue, OnChange, Value), implemented new _OnChange method, and adjusted OnAfterRenderAsync and DisposeAsync for improved JS interop and lifecycle management.
src/BlazorUI/.../MarkdownEditor/BitMarkdownEditor.ts Updated init and constructor signatures to accept additional parameters (dotnetObj, defaultValue), introduced a new static dispose method, and refactored event listener logic (including keydown handling).
src/BlazorUI/.../MarkdownEditor/BitMarkdownEditorJsRuntimeExtensions.cs Modified BitMarkdownEditorInit to include dotnetObj and defaultValue parameters and added a new BitMarkdownEditorDispose method for cleanup via JS interop.
src/BlazorUI/.../MarkdownEditor/BitMarkdownEditor.scss Updated .bit-mde class with height: 100% to ensure the editor uses full container height.
src/BlazorUI/Demo/Client/.../MarkdownEditorDemo.* Restructured demo pages to include new sections and examples demonstrating DefaultValue, OnChange, and two-way binding via Value, with updated code examples.

Sequence Diagram(s)

Loading
sequenceDiagram
    participant User as End User
    participant Editor as BitMarkdownEditor (.razor.cs)
    participant TS as BitMarkdownEditor (TypeScript)
    participant JS as JS Runtime
    participant DotNet as DotNetObjectReference

    User->>JS: Interact with editor (e.g., key press)
    JS-->>Editor: Invoke [_OnChange] via JS interop
    Editor->>Editor: Update Value and trigger OnChange callback
    TS->>TS: Process key events and handle additional content types ("init")
    Editor->>JS: Call BitMarkdownEditorDispose on disposal
    JS->>DotNet: Clean up interop references

Assessment against linked issues

Objective Addressed Explanation
Basic input parameters (Value, DefaultValue, OnChange) [#10271]
Missing disposing functionality [#10271]
Basic keyboard shortcuts (bold, italic, heading) [#10271] No explicit implementation for bold/italic/heading shortcuts is evident.

Poem

I'm a bunny coding with delight,
Hopping through parameters by day and night,
My Markdown editor now sings and swings,
With JS interop and cleaner string things,
Disposal handled, the code feels so bright —
A carrot of joy in each byte!
🥕🐇

Tip

⚡🧪 Multi-step agentic review comment chat (experimental)
  • We're introducing multi-step agentic chat in review comments. This experimental feature enhances review discussions with the CodeRabbit agentic chat by enabling advanced interactions, including the ability to create pull requests directly from comments.
    - To enable this feature, set early_access to true under in the settings.
✨ Finishing Touches
  • 📝 Generate Docstrings

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Generate unit testing code for this file.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai generate unit testing code for this file.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and generate unit testing code.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

Sorry, something went wrong.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

🧹 Nitpick comments (1)
src/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownEditor/BitMarkdownEditor.ts (1)

127-150: Handling of new "init" type.

The method now properly handles the new "init" content type, though it's an empty block. Consider adding a comment explaining the purpose of this empty case.

-            } else if (content.type === "init") { }
+            } else if (content.type === "init") {
+                // No action needed, initialization is handled in the init method
+            }
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 76e1aeb and e61cd23.

📒 Files selected for processing (6)
  • src/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownEditor/BitMarkdownEditor.razor.cs (2 hunks)
  • src/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownEditor/BitMarkdownEditor.scss (1 hunks)
  • src/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownEditor/BitMarkdownEditor.ts (7 hunks)
  • src/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownEditor/BitMarkdownEditorJsRuntimeExtensions.cs (1 hunks)
  • src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Extras/MarkdownEditor/BitMarkdownEditorDemo.razor (1 hunks)
  • src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Extras/MarkdownEditor/BitMarkdownEditorDemo.razor.cs (2 hunks)
🧰 Additional context used
🧬 Code Definitions (2)
src/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownEditor/BitMarkdownEditorJsRuntimeExtensions.cs (2)
src/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownEditor/BitMarkdownEditor.razor.cs (3) (3)
  • ValueTask (38:41)
  • ValueTask (72:86)
  • BitMarkdownEditor (6:87)
src/BlazorUI/Bit.BlazorUI/Components/BitComponentBase.cs (2) (2)
  • ValueTask (196:200)
  • ValueTask (202:206)
src/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownEditor/BitMarkdownEditor.razor.cs (2)
src/BlazorUI/Bit.BlazorUI/Components/BitComponentBase.cs (3) (3)
  • Task (78:147)
  • ValueTask (196:200)
  • ValueTask (202:206)
src/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownEditor/BitMarkdownEditorJsRuntimeExtensions.cs (3) (3)
  • ValueTask (5:12)
  • ValueTask (14:17)
  • ValueTask (19:22)
⏰ Context from checks skipped due to timeout of 90000ms (1)
  • GitHub Check: build and test
🔇 Additional comments (25)
src/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownEditor/BitMarkdownEditor.scss (1)

5-5: Excellent addition to ensure full height usage.

Adding height: 100% to the .bit-mde class ensures the component fills its container's height, which complements the existing width property. This change improves the component's responsiveness and layout behavior.

src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Extras/MarkdownEditor/BitMarkdownEditorDemo.razor (4)

12-17: Well-structured basic demo with consistent height.

The simplified basic demo provides a clean example of the component's usage with a consistent height container.


19-27: Good demonstration of value retrieval.

This section effectively showcases how to retrieve the editor's value programmatically using the reference and GetValue method.


29-36: Excellent demonstration of the OnChange feature.

This example clearly shows how to use the DefaultValue parameter and handle change events, providing visual feedback of the changing value.


38-45: Great two-way binding demonstration.

This example effectively showcases the two-way binding capability using the @bind-Value directive, completing the set of demos for all new features.

src/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownEditor/BitMarkdownEditorJsRuntimeExtensions.cs (2)

5-11: Great enhancement to JS interop initialization.

The addition of dotnetObj and defaultValue parameters to the BitMarkdownEditorInit method enables proper bidirectional communication between JS and .NET, supporting the new change events and default value functionality.


19-22: Essential addition for proper resource cleanup.

Adding the BitMarkdownEditorDispose method ensures proper cleanup of resources when the component is disposed, preventing potential memory leaks and following best practices for component lifecycle management.

src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Extras/MarkdownEditor/BitMarkdownEditorDemo.razor.cs (3)

7-27: Comprehensive documentation of new parameters.

The added component parameters with their types, default values, and descriptions provide excellent documentation for users of the component. The descriptions clearly explain the purpose of each parameter.


39-41: Appropriate state variables for demo sections.

These variables properly support the new demo sections for OnChange and Binding functionality.


64-82: Clear and helpful code examples.

The new code examples for OnChange and Binding features are well-structured and provide valuable reference for users implementing these features in their applications.

src/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownEditor/BitMarkdownEditor.razor.cs (5)

9-9: Good addition of DotNetObjectReference field to manage JavaScript interop lifecycle.

This field correctly enables the communication bridge between C# and JavaScript, allowing for callbacks from JS to .NET.


17-32: Well-structured parameters with appropriate attributes and documentation.

The added parameters enhance the component's functionality:

  • DefaultValue for initialization without binding
  • OnChange callback for event notification
  • Value with TwoWayBound attribute for two-way data binding

These additions follow best practices for Blazor component design.


56-68: Good implementation of conditional DotNetObjectReference creation.

The reference is only created when actually needed (when binding or OnChange handlers are present), which is a performance optimization. The initialization properly passes all required parameters to JavaScript.


72-85: Proper disposal implementation with error handling.

This code correctly:

  1. Disposes the DotNetObjectReference
  2. Calls the JavaScript disposal method
  3. Handles potential JSDisconnectedException
  4. Calls the base disposal method

This implementation ensures clean resource management.


45-50:

❓ Verification inconclusive

Review the implementation of AssignValue method.

The _OnChange method calls AssignValue(value) but this method is not defined in the visible code.


🏁 Script executed:

#!/bin/bash
# Look for implementation of AssignValue method in the base class or component
rg -A 2 "protected\s+(virtual|async)?\s+Task\s+AssignValue" --type csharp

Length of output: 75


I'm not seeing the expected output for the AssignValue method definition. It might be defined in a base class or elsewhere in the codebase with a different signature. To further clarify this, please run a comprehensive search for any occurrence of a method named AssignValue in the repository. For example, try running the following shell script:

Once we have the full output from this search, we'll be better positioned to decide whether the absence of a visible definition is intentional (e.g., inherited from a base class) or if an implementation is actually missing and needs to be added.


🏁 Script executed:

#!/bin/bash
# Perform a comprehensive search for any definition or reference to "AssignValue" in C# files.
rg -n "AssignValue\s*\(" --type csharp

Length of output: 589


I'm not finding an explicit implementation of the AssignValue method in the search results for its definition, though its usage appears in multiple components (including the MarkdownEditor and Slider components).

It is likely that AssignValue is inherited from a common base class. Could you please verify if AssignValue is implemented in one of the base classes (such as a component base used by both MarkdownEditor and Slider)? If so, ensure that the base class implementation meets the expected behavior for MarkdownEditor. If it's missing or improperly defined, you'll need to address that in the base class or override the method in the MarkdownEditor component.

Next Steps:

  • Verify the inheritance hierarchy of BitMarkdownEditor and inspect its base class for the AssignValue implementation.
  • Confirm that the base class correctly implements AssignValue for all derived components.
src/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownEditor/BitMarkdownEditor.ts (10)

4-4: Good addition of "init" type to Content enum.

This addition supports the new initialization flow for the component.


10-15: LGTM: Enhanced initialization with dotnetObj and defaultValue parameters.

This change properly extends the initialization method to support setting a default value and connecting the JavaScript component to the .NET object for callbacks.


27-33: Proper implementation of resource cleanup.

The static dispose method correctly:

  1. Checks if the editor instance exists
  2. Calls the instance's dispose method
  3. Removes the editor from the static map

This prevents memory leaks and ensures proper cleanup.


44-46: Good additions to the pairs map and private fields.

The additions to the pairs map support additional markdown syntax elements, and the new private fields properly manage event handlers and the DotNet reference.

Also applies to: 49-54


56-66: Constructor correctly stores references and binds handlers.

The updated constructor now accepts and stores the DotNet reference and properly binds all event handlers.


76-82: Well-structured initialization of event listeners.

Moving the event listener setup to a dedicated method improves code organization.


181-187: Simplified add method with unified content parameter.

The refactored method correctly uses the content parameter in a consistent way.


235-355: Improved keyboard event handling.

The enhanced keydown handler has significantly improved logic for various key combinations, including:

  • Better handling of special keys
  • More robust code block behavior
  • Improved list handling
  • Enhanced shortcuts for markdown formatting

The code is well-structured and handles edge cases properly.


357-375: Well-implemented event handlers.

The event handlers for double-click, click, and change events are properly implemented:

  • dblClick improves selection behavior
  • click resets the opens array
  • change correctly triggers the .NET callback

The callback to OnChange method in line 373 is essential for the two-way binding to work.


376-384: Thorough cleanup in dispose method.

The dispose method correctly:

  1. Removes all event listeners
  2. Clears the DotNet reference

This prevents memory leaks and ensures proper cleanup.

@msynk msynk merged commit 6897a70 into bitfoundation:develop Mar 18, 2025
3 checks passed
@msynk msynk deleted the 10271-blazorui-markdowneditor-improvements branch March 18, 2025 11:52
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

The BitMarkdownEditor improvements
2 participants