-
-
Notifications
You must be signed in to change notification settings - Fork 235
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
Add MarkdownViewer extra component (#10111) #10211
base: develop
Are you sure you want to change the base?
Add MarkdownViewer extra component (#10111) #10211
Conversation
Important Review skippedAuto incremental reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the You can disable this status message by setting the WalkthroughThe changes introduce a new MarkdownViewer component in the Bit.BlazorUI.Extras library. This includes Razor and code-behind files to render Markdown content using the markedjs library, supporting JS interop and custom styling. Additional TypeScript, SCSS, and JavaScript files facilitate initialization, parsing, and styling. The demo application is updated with a dedicated page, navigation links, and configuration adjustments to showcase the new MarkdownViewer. Changes
Sequence Diagram(s)sequenceDiagram
participant Component as BitMarkdownViewer Component
participant JSRuntime as IJSRuntime
participant ViewerTS as MarkdownViewer (TS)
participant MarkedJS as Marked (JS Library)
Component->>JSRuntime: Call BitMarkdownViewerInit(scripts)
JSRuntime->>ViewerTS: Load and initialize scripts
Component->>JSRuntime: Call BitMarkdownViewerParse(Markdown)
JSRuntime->>ViewerTS: Execute parse method
ViewerTS->>MarkedJS: Process Markdown via markedjs
MarkedJS-->>ViewerTS: Return parsed HTML
ViewerTS-->>JSRuntime: Deliver parsed HTML
JSRuntime-->>Component: Return HTML markup
Component->>Component: Update UI with new HTML
Poem
🪧 TipsChatThere are 3 ways to chat with CodeRabbit:
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)
Other keywords and placeholders
CodeRabbit Configuration File (
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 1
🧹 Nitpick comments (12)
src/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/BitMarkdownViewer.scss (1)
6-8
: Consider if a more targeted reset approach is needed.Using
all: revert
on all child elements is a heavy-handed approach. This might cause inconsistencies if specific elements within the Markdown content need custom styling. Consider whether a more targeted reset for specific elements might be more appropriate.src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Extras/MarkdownViewer/BitMarkdownViewerDemo.razor.scss (1)
1-7
: Consider moving responsive image styling to the component itself.The responsive image styling is appropriate for ensuring images scale properly, but this behavior might be desirable for all implementations of the MarkdownViewer, not just the demo. Consider moving this style to the component's base SCSS file so all implementers benefit from responsive images by default.
// In BitMarkdownViewer.scss .bit-mdv { all: revert; * { all: revert; } + + img { + max-width: 100%; + } }src/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/BitMarkdownViewer.ts (2)
2-41
: Consider refactoring to use standalone functions instead of a static class.The
MarkdownViewer
class contains only static methods, which is flagged by static analysis. Consider using standalone functions within the namespace for a more functional approach.namespace BitBlazorUI { - export class MarkdownViewer { - private static _initPromise?: Promise<unknown>; + let _initPromise?: Promise<unknown>; - public static async init(scripts: string[]) { + export async function init(scripts: string[]) { - if (MarkdownViewer._initPromise) { - await MarkdownViewer._initPromise; + if (_initPromise) { + await _initPromise; } const allScripts = Array.from(document.scripts).map(s => s.src); const notAppenedScripts = scripts.filter(s => !allScripts.find(as => as.endsWith(s))); if (notAppenedScripts.length == 0) return Promise.resolve(); const promise = new Promise(async (resolve: any, reject: any) => { try { for (let url of notAppenedScripts) await addScript(url); resolve(); } catch (e: any) { reject(e); } }); - MarkdownViewer._initPromise = promise; + _initPromise = promise; return promise; async function addScript(url: string) { return new Promise((res, rej) => { const script = document.createElement('script'); script.src = url; script.onload = res; script.onerror = rej; document.body.appendChild(script); }) } } - public static async parse(md: string) { + export async function parse(md: string) { const html = await marked.parse(md, { async: true }); return html; } - } }🧰 Tools
🪛 Biome (1.9.4)
[error] 2-41: Avoid classes that contain only static members.
Prefer using simple functions instead of classes with only static members.
(lint/complexity/noStaticOnlyClass)
[error] 15-22: Promise executor functions should not be
async
.(lint/suspicious/noAsyncPromiseExecutor)
11-12
: Correct typo in variable namenotAppenedScripts
.There's a typo in the variable name
notAppenedScripts
. It should benotAppendedScripts
.- const notAppenedScripts = scripts.filter(s => !allScripts.find(as => as.endsWith(s))); + const notAppendedScripts = scripts.filter(s => !allScripts.find(as => as.endsWith(s)));src/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/BitMarkdownViewerJsRuntimeExtensions.cs (2)
3-4
: Consider changing the access modifier to match component usage patterns.The class is marked internal but contains public methods. If this is intended to be used only within the library, consider making the methods internal as well for consistency.
-internal static class BitMarkdownViewerJsRuntimeExtensions +internal static class BitMarkdownViewerJsRuntimeExtensions { - public static ValueTask BitMarkdownViewerInit(this IJSRuntime jsRuntime, IEnumerable<string> scripts) + internal static ValueTask BitMarkdownViewerInit(this IJSRuntime jsRuntime, IEnumerable<string> scripts) { return jsRuntime.InvokeVoid("BitBlazorUI.MarkdownViewer.init", scripts); } - public static ValueTask<string> BitMarkdownViewerParse(this IJSRuntime jsRuntime, string markdown) + internal static ValueTask<string> BitMarkdownViewerParse(this IJSRuntime jsRuntime, string markdown) { return jsRuntime.Invoke<string>("BitBlazorUI.MarkdownViewer.parse", markdown); } }
1-14
: Add missing using directives and parameter documentation.The file is missing using directives for
System.Threading.Tasks
andMicrosoft.JSInterop
. Also consider adding XML documentation for the methods and parameters.namespace Bit.BlazorUI; + +using System.Threading.Tasks; +using Microsoft.JSInterop; internal static class BitMarkdownViewerJsRuntimeExtensions { + /// <summary> + /// Initializes the Markdown viewer by loading required scripts. + /// </summary> + /// <param name="jsRuntime">The JS runtime instance.</param> + /// <param name="scripts">The list of script URLs to load.</param> + /// <returns>A ValueTask representing the asynchronous operation.</returns> public static ValueTask BitMarkdownViewerInit(this IJSRuntime jsRuntime, IEnumerable<string> scripts) { return jsRuntime.InvokeVoid("BitBlazorUI.MarkdownViewer.init", scripts); } + /// <summary> + /// Parses Markdown content into HTML. + /// </summary> + /// <param name="jsRuntime">The JS runtime instance.</param> + /// <param name="markdown">The Markdown content to parse.</param> + /// <returns>A ValueTask containing the HTML string result.</returns> public static ValueTask<string> BitMarkdownViewerParse(this IJSRuntime jsRuntime, string markdown) { return jsRuntime.Invoke<string>("BitBlazorUI.MarkdownViewer.parse", markdown); } }src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Extras/MarkdownViewer/BitMarkdownViewerDemo.razor (2)
5-5
: Fix inconsistent casing in description.The description uses lowercase "markdownviewer" which is inconsistent with the component name "MarkdownViewer" used elsewhere.
- Description="markdownviewer component of the bit BlazorUI components" /> + Description="MarkdownViewer component of the bit BlazorUI components" />
17-21
: Consider adding responsive image styling by default.In the advanced example, you're wrapping the
BitMarkdownViewer
in a div without any purpose. Consider adding the responsive image styles directly to the component parameters.- <DemoSection Title="Advanced" RazorCode="@example2RazorCode" CsharpCode="@example2CsharpCode" Id="example2"> - <div> - <BitMarkdownViewer Markdown="@advancedMarkdown" Class="advanced" /> - </div> + <DemoSection Title="Advanced" RazorCode="@example2RazorCode" CsharpCode="@example2CsharpCode" Id="example2"> + <BitMarkdownViewer Markdown="@advancedMarkdown" Class="advanced" /> </DemoSection>src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Extras/MarkdownViewer/BitMarkdownViewerDemo.razor.cs (3)
5-14
: Consider adding more component parameters.The demo page only shows one parameter "Markdown" for the BitMarkdownViewer component. If there are other parameters like "Class" that can be used, consider adding them to the componentParameters list.
private readonly List<ComponentParameter> componentParameters = [ new() { Name = "Markdown", Type = "string?", DefaultValue = "null", Description = "The Markdown string value to render as an html element.", }, + new() + { + Name = "Class", + Type = "string?", + DefaultValue = "null", + Description = "Additional CSS class to apply to the component." + } ];
93-106
: Inconsistent string interpolation in example code.The example code uses string interpolation with raw strings which would require many escape characters in real C# code. Consider simplifying to improve readability.
For example2RazorCode, you might want to use a verbatim string without escaping double quotes:
- private readonly string example1RazorCode = @" -<BitMarkdownViewer Markdown=""@(""# Marked in the browser\n\nRendered by **marked**."")"" />"; + private readonly string example1RazorCode = @" +<BitMarkdownViewer Markdown=""@(""# Marked in the browser\n\nRendered by **marked**."")"" />";This is a minor issue, but could be confusing to developers looking at the demo.
25-26
: Simplify Markdown string with verbatim strings.The Markdown string has many escape sequences for double quotes. Consider using C#'s verbatim string literals with alternate quote delimiter to simplify this.
In C# 11+ you can use raw string literals with triple quotes to avoid escaping:
-[](http://isitmaintained.com/project/bitfoundation/bitplatform ""Average time to resolve an issue"") -[](http://isitmaintained.com/project/bitfoundation/bitplatform ""Percentage of issues still open"") +[](http://isitmaintained.com/project/bitfoundation/bitplatform """Average time to resolve an issue""") +[](http://isitmaintained.com/project/bitfoundation/bitplatform """Percentage of issues still open""")src/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/marked.d.ts (1)
609-609
: Avoid confusing 'void' in union types
Static analysis highlights that usingvoid
within a union type can be misleading. Replace it withundefined
or rework the type to be more descriptive (e.g.,null | Promise<void>
).- declare type MaybePromise = void | Promise<void>; + declare type MaybePromise = undefined | Promise<void>;
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (15)
src/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/BitMarkdownViewer.razor
(1 hunks)src/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/BitMarkdownViewer.razor.cs
(1 hunks)src/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/BitMarkdownViewer.scss
(1 hunks)src/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/BitMarkdownViewer.ts
(1 hunks)src/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/BitMarkdownViewerJsRuntimeExtensions.cs
(1 hunks)src/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/marked.d.ts
(1 hunks)src/BlazorUI/Bit.BlazorUI.Extras/Styles/bit.blazorui.extras.scss
(1 hunks)src/BlazorUI/Bit.BlazorUI.Extras/Styles/extra-components.scss
(1 hunks)src/BlazorUI/Bit.BlazorUI.Extras/wwwroot/marked/marked-15.0.7.js
(1 hunks)src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Extras/MarkdownViewer/BitMarkdownViewerDemo.razor
(1 hunks)src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Extras/MarkdownViewer/BitMarkdownViewerDemo.razor.cs
(1 hunks)src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Extras/MarkdownViewer/BitMarkdownViewerDemo.razor.scss
(1 hunks)src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Home/ComponentsSection.razor
(1 hunks)src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Shared/MainLayout.razor.NavItems.cs
(1 hunks)src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/compilerconfig.json
(1 hunks)
🧰 Additional context used
🪛 Biome (1.9.4)
src/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/BitMarkdownViewer.ts
[error] 2-41: Avoid classes that contain only static members.
Prefer using simple functions instead of classes with only static members.
(lint/complexity/noStaticOnlyClass)
[error] 15-22: Promise executor functions should not be async
.
(lint/suspicious/noAsyncPromiseExecutor)
src/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/marked.d.ts
[error] 401-401: void is confusing inside a union type.
Unsafe fix: Use undefined instead.
(lint/suspicious/noConfusingVoidType)
src/BlazorUI/Bit.BlazorUI.Extras/wwwroot/marked/marked-15.0.7.js
[error] 6-6: Redundant use strict directive.
The entire contents of JavaScript modules are automatically in strict mode, with no statement needed to initiate it.
Safe fix: Remove the redundant use strict directive.
(lint/suspicious/noRedundantUseStrict)
[error] 6-6: Unexpected control character in a regular expression.
Control characters are unusual and potentially incorrect inputs, so they are disallowed.
(lint/suspicious/noControlCharactersInRegex)
[error] 6-6: Unexpected control character in a regular expression.
Control characters are unusual and potentially incorrect inputs, so they are disallowed.
(lint/suspicious/noControlCharactersInRegex)
[error] 6-6: Unexpected control character in a regular expression.
Control characters are unusual and potentially incorrect inputs, so they are disallowed.
(lint/suspicious/noControlCharactersInRegex)
[error] 6-6: Unexpected control character in a regular expression.
Control characters are unusual and potentially incorrect inputs, so they are disallowed.
(lint/suspicious/noControlCharactersInRegex)
⏰ Context from checks skipped due to timeout of 90000ms (1)
- GitHub Check: build and test
🔇 Additional comments (11)
src/BlazorUI/Bit.BlazorUI.Extras/Styles/extra-components.scss (1)
6-6
: Import for the new MarkdownViewer component looks good.The import is properly placed following the alphabetical order of the existing component imports.
src/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/BitMarkdownViewer.scss (1)
3-9
:❓ Verification inconclusive
Consider browser compatibility with the
all: revert
property.The
all: revert
approach effectively resets styles to browser defaults, which is good for Markdown content. However, be aware that this property might have limited support in older browsers. Consider documenting this requirement or providing fallback styles for browsers that don't support this property.
🌐 Web query:
Browser compatibility for CSS all:revert property
💡 Result:
The
all: revert
CSS property resets an element's styles to the browser's default user-agent stylesheet values, ignoring any author-defined CSS. This is particularly useful for overriding inherited styles or resetting components to their base appearance. Browser support is generally good in modern browsers, with some limitations in older versions.Browser Compatibility Overview
Browser Supported Versions Notes Chrome 84+ (✅ Full support) Pre-Chrome 84 lacks support [1][2] Firefox 67+ (✅ Full support) Earlier versions unsupported [1][2][7] Safari 9.1+ (✅ Full support) iOS Safari 9.3+ supported [1][2] Edge 84+ (✅ Full support) Legacy Edge (12-83) unsupported [1][2] Opera 73+ (✅ Full support) Internet Explorer ❌ No support All IE versions lack support [1][2] Key Details
Mobile Browsers:
- Chrome for Android/Firefox for Android: Full support [1][2]
- Samsung Internet: 14+ [2]
- iOS Safari: 9.3+ [1][2]
Special Cases:
revert
works as a standalone value (e.g.,color: revert
) and withall
[7][8].- Older browsers like Chrome ≤83 or Firefox ≤66 will ignore
revert
entirely [1][2].Practical Considerations
- Fallbacks: Use
unset
orinitial
as progressive enhancements for older browsers [3][7].- Reset Scope:
all: revert
affects all properties exceptdirection
andunicode-bidi
[8].- Cascade Layers: In modern browsers,
revert-layer
provides more granular control [4].For projects requiring IE11 support, avoid
all: revert
entirely. Always test on target browsers using tools like LambdaTest[1] or CanIUse[2] to verify compatibility.Citations:
- 1: https://www.lambdatest.com/web-technologies/css-revert-value
- 2: https://caniuse.com/css-revert-value
- 3: https://css-tricks.com/what-does-revert-do-in-css/
- 4: https://blog.logrocket.com/understanding-css-revert-layer/
- 5: https://blog.pixelfreestudio.com/how-to-ensure-cross-browser-compatibility-with-css/
- 6: https://www.lambdatest.com/web-technologies/css-all
- 7: https://developer.mozilla.org/en-US/docs/Web/CSS/revert
- 8: https://developer.mozilla.org/en-US/docs/Web/CSS/all
- 9: https://www.w3schools.com/cssref/css3_browsersupport.php
Attention: Browser Compatibility Consideration
Your Markdown viewer’s CSS reset using
all: revert
is effective for reverting styles to the browser’s default user-agent settings. However, note that while modern browsers (e.g., Chrome 84+, Firefox 67+, Safari 9.1+, Edge 84+, and Opera 73+) fully support this property, legacy browsers—most notably Internet Explorer and pre-Chrome 84/Firefox 67 versions—do not.
- Please verify if support for these older browsers is required.
- If so, consider adding fallback styles (using alternatives like
unset
orinitial
) or document this limitation clearly within the project’s guidelines or inline comments.src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Shared/MainLayout.razor.NavItems.cs (1)
159-159
: Navigation item placement is correct.The MarkdownViewer navigation item is appropriately placed in the "Extras" category, following the same pattern as other components.
src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Home/ComponentsSection.razor (1)
265-267
: Link for MarkdownViewer component added correctly.The new BitLink component for MarkdownViewer follows the established pattern and maintains consistent styling with other component links in the Extras section.
src/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/BitMarkdownViewer.razor (1)
1-11
: Component structure follows BitComponentBase pattern appropriately.The component is properly structured with:
- Correct namespace declaration
- Inheritance from BitComponentBase
- Appropriate div element with reference, attributes, and styling
- Proper handling of Markdown content via MarkupString
The implementation aligns with the architectural patterns used in other Bit.BlazorUI components.
src/BlazorUI/Bit.BlazorUI.Extras/Styles/bit.blazorui.extras.scss (1)
1-2
: Import statements updated to use more specific stylesheets.The change from generic "general.scss" and "components.scss" to more specific "extra-general.scss" and "extra-components.scss" improves organization by better separating core and extra component styles.
src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/compilerconfig.json (1)
80-85
: Compiler configuration for BitMarkdownViewerDemo properly added.The new configuration entry for BitMarkdownViewerDemo follows the same pattern as other components, with appropriate output/input paths and consistent minify/sourceMap settings.
src/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/BitMarkdownViewer.ts (1)
37-40
: Add error handling for the marked library dependency.The
parse
method assumes that themarked
library is available globally, but there's no check to verify this. If the library isn't loaded, this will cause runtime errors.Consider adding a check for the
marked
library's availability before using it:public static async parse(md: string) { + if (typeof marked === 'undefined') { + throw new Error('The marked library is not loaded. Make sure to call init() first.'); + } const html = await marked.parse(md, { async: true }); return html; }src/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/BitMarkdownViewer.razor.cs (2)
1-7
: Overall Implementation Looks Good
No errors are detected in the fundamental structure, parameter declarations, or the class definition. The summary documentation is clear and concise, and the code style is consistent.
33-33
: Verify the method name for JavaScript initialization
The method_js.BitPdfReaderInit
appears to be mismatched for a Markdown viewer context. It may be a leftover reference from a PDF component. Consider renaming it to match the Markdown functionality if that is the intended usage.Would you like me to open a new issue to rename it (e.g.,
_js.BitMarkdownViewerInit
) for clarity?src/BlazorUI/Bit.BlazorUI.Extras/wwwroot/marked/marked-15.0.7.js (1)
6-6
: Address static analysis findings or confirm integrity of third-party code
Static analysis reports a redundant'use strict'
directive and potential control characters in the regular expressions. Usually, this file is an external dependency, so modifying minified library code may be risky. Verify if an official distribution of the same version can replace or confirm no actual harmful control characters are present.🧰 Tools
🪛 Biome (1.9.4)
[error] 6-6: Redundant use strict directive.
The entire contents of JavaScript modules are automatically in strict mode, with no statement needed to initiate it.
Safe fix: Remove the redundant use strict directive.(lint/suspicious/noRedundantUseStrict)
[error] 6-6: Unexpected control character in a regular expression.
Control characters are unusual and potentially incorrect inputs, so they are disallowed.
(lint/suspicious/noControlCharactersInRegex)
[error] 6-6: Unexpected control character in a regular expression.
Control characters are unusual and potentially incorrect inputs, so they are disallowed.
(lint/suspicious/noControlCharactersInRegex)
[error] 6-6: Unexpected control character in a regular expression.
Control characters are unusual and potentially incorrect inputs, so they are disallowed.
(lint/suspicious/noControlCharactersInRegex)
[error] 6-6: Unexpected control character in a regular expression.
Control characters are unusual and potentially incorrect inputs, so they are disallowed.
(lint/suspicious/noControlCharactersInRegex)
src/BlazorUI/Bit.BlazorUI.Extras/Components/MarkdownViewer/BitMarkdownViewer.ts
Outdated
Show resolved
Hide resolved
….com/msynk/bitframework into 10111-blazorui-extra-markdown-viewer
closes #10111
Summary by CodeRabbit
New Features
Style