Skip to content

Add ProModal component (#9503)#12420

Open
msynk wants to merge 11 commits into
bitfoundation:developfrom
msynk:9503-blazorui-extras-promodal-ii
Open

Add ProModal component (#9503)#12420
msynk wants to merge 11 commits into
bitfoundation:developfrom
msynk:9503-blazorui-extras-promodal-ii

Conversation

@msynk

@msynk msynk commented Jun 1, 2026

Copy link
Copy Markdown
Member

closes #9503

Summary by CodeRabbit

  • New Features

    • Introduced BitProModal component with advanced capabilities: draggable modals, absolute/fixed positioning, auto-scroll toggling, customizable header/footer/body templates, configurable close button, and flexible styling options.
  • Changes

    • Simplified BitModal by removing advanced features (Modeless, Blocking, Draggable, Position, auto-scroll) now exclusive to BitProModal; added AriaModal and ShowOverlay parameters for better control.

@coderabbitai

coderabbitai Bot commented Jun 1, 2026

Copy link
Copy Markdown

Review Change Stack

Important

Review skipped

Auto incremental reviews are disabled on this repository.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: 733a450a-a77a-4cda-8a5d-b5a13e2731b9

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review

Walkthrough

This PR introduces the BitProModal component to Bit.BlazorUI.Extras—a feature-rich modal wrapper around BitModal supporting advanced behaviors such as drag-drop, scroll auto-toggle, absolute positioning, and full customization via slots and parameters. Concurrently, it refactors BitModal to remove advanced features now exclusive to BitProModal, simplifies service registration, generalizes JS drag-drop interop, and updates demo pages and tests accordingly.

Changes

BitProModal and coordinated platform updates

Layer / File(s) Summary
CSS class customization and SCSS styling foundations
src/BlazorUI/Bit.BlazorUI.Extras/Components/ProModal/BitProModalClassStyles.cs, src/BlazorUI/Bit.BlazorUI.Extras/Components/ProModal/BitProModal.scss, src/BlazorUI/Bit.BlazorUI.Extras/Styles/extra-components.scss
Adds BitProModalClassStyles extending BitModalClassStyles with properties for header/footer/body/close-button CSS customization, and defines .bit-pmd base styling with overlay, flex layout, sticky header/footer, scrollable body, and close-button interaction states; registers ProModal styles in extras stylesheet.
BitProModal Razor component structure
src/BlazorUI/Bit.BlazorUI.Extras/Components/ProModal/BitProModal.razor
Introduces BitProModal namespace and inheritance, wires inner BitModal with ARIA/overlay/callback forwarding, conditionally renders header with Header slot preference over HeaderText and optional close button with icon customization, implements body/footer content selection with slot precedence.
BitProModal parameters and lifecycle
src/BlazorUI/Bit.BlazorUI.Extras/Components/ProModal/BitProModal.razor.cs
Defines full public parameter API (templates, sizing, positioning, drag, scroll, ARIA, callbacks), two-way IsOpen binding with Open/Close methods, CSS class/style registration based on mode/position/size, OnAfterRenderAsync open/close lifecycle with conditional drag-drop setup and scroll toggling, interaction handlers, and DisposeAsync cleanup.
Generalized drag-drop JS interop
src/BlazorUI/Bit.BlazorUI/Extensions/JsInterop/DragDropJsRuntimeExtensions.cs, src/BlazorUI/Bit.BlazorUI/Scripts/DragDrop.ts, src/BlazorUI/Bit.BlazorUI/Components/Surfaces/Dialog/BitDialog.razor.cs
Introduces DragDrop TypeScript utility with pointer-based setup/remove replacing Modal-specific drag-drop; adds IJSRuntime extension methods for C# interop; updates BitDialog to use generalized extensions.
BitModal API simplification and parameter removal
src/BlazorUI/Bit.BlazorUI/Components/Surfaces/Modal/BitModal.razor*, src/BlazorUI/Bit.BlazorUI/Components/Surfaces/Modal/BitModalParameters.cs, src/BlazorUI/Bit.BlazorUI/Components/Surfaces/Modal/BitModalJsRuntimeExtensions.cs, src/BlazorUI/Bit.BlazorUI.Extras/Components/ModalService/*, src/BlazorUI/Bit.BlazorUI.Extras/Extensions/IBlazorUIExtrasServiceCollectionExtensions.cs
Adds AriaModal and ShowOverlay parameters; removes Modeless; simplifies CSS class/style registration; changes overlay-click flow to invoke OnOverlayClick unconditionally; simplifies ARIA role selection. Removes BitModalJsRuntimeExtensions and prunes BitModalParameters (AutoToggleScroll, AbsolutePosition, Blocking, Draggable, FullSize, Modeless, Position, scroll fields). Updates BitModalService overlay-click wiring. Cleans up BitModalContainer/Reference whitespace. Adds base service registration call in Extras DI.
Dependency injection registration updates
src/BlazorUI/Bit.BlazorUI/Extensions/IBitBlazorUIServiceCollectionExtensions.cs
Adds XML documentation to AddBitBlazorUIServices.
Demo pages with comprehensive examples
src/BlazorUI/Demo/Client/.../ProModal/BitProModalDemo.razor*, src/BlazorUI/Demo/Client/.../Surfaces/Modal/BitModalDemo.razor*, src/BlazorUI/Demo/Client/.../Extras/ModalService/BitModalServiceDemo.razor*, src/BlazorUI/Demo/Client/.../Home/ComponentsSection.razor, src/BlazorUI/Demo/Client/.../Shared/MainLayout.razor*
Adds BitProModalDemo with 11 example sections and comprehensive documentation metadata. Updates BitModalDemo to contrast with BitProModal, adds Blocking/Events examples, removes Position-driven examples. Updates BitModalServiceDemo examples. Reorganizes navigation moving ModalService to Surfaces and adding ProModal to Extras.
Component tests and test reorganization
src/BlazorUI/Tests/.../ProModal/BitProModalTests.cs, src/BlazorUI/Tests/.../Modal/BitModalServiceTests.cs, src/BlazorUI/Tests/.../Modal/BitModalTests.cs, src/BlazorUI/Tests/.../Modal/TestModalContent.cs
Adds comprehensive BitProModalTests covering modeless/blocking modes, ARIA, interaction, layout modifiers, and content rendering. Reorganizes test namespaces to Surfaces.Modal; adds FullWidth parameter test. Removes obsolete BitModal tests (IsBlockingTest, IsModelessTest, BitPositionTest) reflecting feature migration to BitProModal.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Poem

🐰 A modal so pro joins the extras array,
With dragging and scrolling in grand display!
The base modal slims down, so lean and so light,
While BitProModal dons all the new might—
From positioning free to callbacks so bright! 🚀

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 6.56% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The pull request title 'Add ProModal component (#9503)' clearly and concisely describes the main change—adding a new ProModal component to the Extras project, which is the primary objective of this PR.
Linked Issues check ✅ Passed The PR successfully implements the primary objective from issue #9503: the BitProModal component is now included in the Extras project with complete implementation, documentation, and tests.
Out of Scope Changes check ✅ Passed While the PR includes refactoring of BitModal and related components (removal of drag-drop/scroll features moved to ProModal), these changes are necessary supporting modifications to enable the new ProModal component and maintain API consistency.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

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

Comment @coderabbitai help to get the list of available commands and usage tips.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/BlazorUI/Bit.BlazorUI.Extras/Components/ProModal/BitProModal.razor.cs`:
- Around line 23-26: The XML doc for the Blocking parameter is incorrect: it
currently says “Whether the Modal can be light dismissed…”, but Blocking
actually prevents light-dismiss when true (overlay click handler returns early
when ModalParameters.Blocking is true). Update the summary for the Blocking
property in BitProModal (and the duplicated summaries in BitProModalDemo and any
BitModal references) to state that when true the modal cannot be light-dismissed
by clicking the overlay; when false overlay clicks allow dismissal. Ensure the
wording clearly indicates the boolean semantics (true = prevents light-dismiss,
false = allows it).

In `@src/BlazorUI/Bit.BlazorUI.Extras/Components/ProModal/BitProModal.scss`:
- Line 1: In BitProModal.scss update the `@import` to omit the .scss extension
(change the import of 'functions.scss' to 'functions') to satisfy the stylelint
rule scss/load-partial-extension; locate the `@import` line in BitProModal.scss
that references '../../../Bit.BlazorUI/Styles/functions.scss' and remove the
'.scss' suffix (or alternatively add/configure a stylelint suppression/baseline
for this rule if you intend to keep extensions across Extras files).
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: 839c5e64-71a6-48d0-8212-86f5b4be13b0

📥 Commits

Reviewing files that changed from the base of the PR and between 046d116 and 082ef02.

📒 Files selected for processing (10)
  • src/BlazorUI/Bit.BlazorUI.Extras/Components/ProModal/BitProModal.razor
  • src/BlazorUI/Bit.BlazorUI.Extras/Components/ProModal/BitProModal.razor.cs
  • src/BlazorUI/Bit.BlazorUI.Extras/Components/ProModal/BitProModal.scss
  • src/BlazorUI/Bit.BlazorUI.Extras/Components/ProModal/BitProModalClassStyles.cs
  • src/BlazorUI/Bit.BlazorUI.Extras/Styles/extra-components.scss
  • src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Extras/ProModal/BitProModalDemo.razor
  • src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Extras/ProModal/BitProModalDemo.razor.cs
  • src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Extras/ProModal/BitProModalDemo.razor.scss
  • src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Home/ComponentsSection.razor
  • src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Shared/MainLayout.razor.NavItems.cs

@msynk

msynk commented Jun 9, 2026

Copy link
Copy Markdown
Member Author

@coderabbitai re-review

@coderabbitai

coderabbitai Bot commented Jun 9, 2026

Copy link
Copy Markdown

@msynk: I'll re-review the PR now.

✅ Action performed

Full review finished.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 4

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
src/BlazorUI/Bit.BlazorUI/Components/Surfaces/Dialog/BitDialog.ts (1)

59-65: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

removeDragDrop can leak listener state when the drag element is already unmounted.

When querySelector returns null, the function returns before removing document listeners and deleting the registry entry.

Suggested patch
 public static removeDragDrop(id: string, dragElementSelector: string) {
     const listeners = Dialog._dragDropListeners[id];
     if (!listeners) return;

     const dragElement = document.querySelector(dragElementSelector)! as HTMLElement;
-    if (!dragElement) return;
-
-    dragElement.removeEventListener('pointerdown', listeners['pointerdown']);
-    dragElement.style.cursor = '';
-    dragElement.classList.remove('bit-mdl-nta');
+    if (dragElement) {
+        dragElement.removeEventListener('pointerdown', listeners['pointerdown']);
+        dragElement.style.cursor = '';
+        dragElement.classList.remove('bit-mdl-nta');
+    }

     document.removeEventListener('pointermove', listeners['pointermove']);
     document.removeEventListener('pointerup', listeners['pointerup']);

     delete listeners['pointerdown'];
     delete listeners['pointermove'];
     delete listeners['pointerup'];
     delete Dialog._dragDropListeners[id];
 }

Also applies to: 70-80

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/BlazorUI/Bit.BlazorUI/Components/Surfaces/Dialog/BitDialog.ts` around
lines 59 - 65, removeDragDrop currently exits early if
document.querySelector(dragElementSelector) returns null, leaking the entry in
Dialog._dragDropListeners and leaving document listeners attached; instead,
always read Dialog._dragDropListeners[id] and, even when dragElement is null,
remove the stored document-level listeners (using the listener functions from
the listeners object) and then delete Dialog._dragDropListeners[id]; only skip
element-specific cleanup when dragElement is null. Apply the same fix to the
other branch/duplicate logic around lines 70-80 that also assumes the element
exists.
🧹 Nitpick comments (4)
src/BlazorUI/Bit.BlazorUI.Extras/Components/ProModal/BitProModal.razor.cs (1)

246-285: 💤 Low value

Consider adding clarifying comments for _offsetTop and AbsolutePosition logic.

The lifecycle logic is correct but subtle:

  1. Line 259 sets _offsetTop = 0 before calling ToggleScroll. This appears redundant since ToggleScroll (lines 341, 345) overwrites _offsetTop, but it's actually a guard for when AutoToggleScroll is false (line 337 early return).

  2. Lines 263-267 reset and re-render only for AbsolutePosition. This ensures the top offset style (registered on line 243) is applied after ToggleScroll calculates the scroll offset.

📝 Suggested clarifying comments
-                _offsetTop = 0;
+                // Reset offset; will be recalculated by ToggleScroll if AutoToggleScroll is enabled
+                _offsetTop = 0;

                 await ToggleScroll(true);
                 
                 if (AbsolutePosition)
                 {
+                    // Re-render to apply the calculated top offset style for absolute positioning
                     StyleBuilder.Reset();
                     StateHasChanged();
                 }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/BlazorUI/Bit.BlazorUI.Extras/Components/ProModal/BitProModal.razor.cs`
around lines 246 - 285, Add brief clarifying comments inside OnAfterRenderAsync
around the _offsetTop and AbsolutePosition logic: comment why _offsetTop = 0 is
set before calling ToggleScroll (it's a guard for the case when AutoToggleScroll
is false and ToggleScroll will not recalc _offsetTop), and comment why
StyleBuilder.Reset() and StateHasChanged() are invoked only when
AbsolutePosition is true (to ensure the computed top-offset style, which
ToggleScroll may have updated, is applied after render). Reference the symbols
_offsetTop, ToggleScroll, AutoToggleScroll, AbsolutePosition,
StyleBuilder.Reset, and OnAfterRenderAsync when placing the comments.
src/BlazorUI/Bit.BlazorUI.Extras/Components/ProModal/BitProModalClassStyles.cs (1)

3-34: ⚡ Quick win

Consider adding a Merge method for BitProModalClassStyles.

The base BitModalClassStyles provides a static Merge method, but it only merges the base properties (Root, Overlay, Content). When BitProModalClassStyles instances need to be merged, the derived properties (HeaderContainer, Header, CloseButton, CloseIcon, Body, Footer) will be lost.

📦 Proposed Merge method
+    public static BitProModalClassStyles Merge(BitProModalClassStyles? classStyles1, BitProModalClassStyles? classStyles2)
+    {
+        var baseStyles = BitModalClassStyles.Merge(classStyles1, classStyles2);
+        return new BitProModalClassStyles
+        {
+            Root = baseStyles.Root,
+            Overlay = baseStyles.Overlay,
+            Content = baseStyles.Content,
+            HeaderContainer = classStyles1?.HeaderContainer ?? classStyles2?.HeaderContainer,
+            Header = classStyles1?.Header ?? classStyles2?.Header,
+            CloseButton = classStyles1?.CloseButton ?? classStyles2?.CloseButton,
+            CloseIcon = classStyles1?.CloseIcon ?? classStyles2?.CloseIcon,
+            Body = classStyles1?.Body ?? classStyles2?.Body,
+            Footer = classStyles1?.Footer ?? classStyles2?.Footer
+        };
+    }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/ProModal/BitProModalClassStyles.cs`
around lines 3 - 34, The BitProModalClassStyles class lacks a Merge method so
derived properties (HeaderContainer, Header, CloseButton, CloseIcon, Body,
Footer) are not preserved when merging; add a static
Merge(BitProModalClassStyles? first, BitProModalClassStyles? second) that calls
BitModalClassStyles.Merge for base fields then merges each derived string
property (choose non-null/longer/concatenate as project convention) into the
result, ensuring the returned BitProModalClassStyles contains merged values for
Root/Overlay/Content plus HeaderContainer, Header, CloseButton, CloseIcon, Body,
and Footer.
src/BlazorUI/Bit.BlazorUI.Extras/Components/ProModal/BitProModal.scss (1)

37-110: ⚖️ Poor tradeoff

Significant duplication in positioning classes.

Six pairs of positioning classes are identical, resulting in 36+ lines of duplicate CSS:

  • .bit-mdl-tlf (TopLeft) = .bit-mdl-tst (TopStart)
  • .bit-mdl-trg (TopRight) = .bit-mdl-ten (TopEnd)
  • .bit-mdl-clf (CenterLeft) = .bit-mdl-cst (CenterStart)
  • .bit-mdl-crg (CenterRight) = .bit-mdl-cen (CenterEnd)
  • .bit-mdl-blf (BottomLeft) = .bit-mdl-bst (BottomStart)
  • .bit-mdl-brg (BottomRight) = .bit-mdl-ben (BottomEnd)

Additionally, this causes incorrect RTL behavior: absolute directions (Left/Right) currently use flexbox flex-start/flex-end, which adapt to the dir attribute. In RTL mode, TopLeft will incorrectly position on the right. Absolute directions should use fixed positioning (left: 0, right: 0) while logical directions (Start/End) should continue using flexbox.

🎨 Refactor approach

For absolute directions, replace flexbox with explicit positioning:

.bit-mdl-tlf {
    top: 0;
    left: 0;
}

.bit-mdl-trg {
    top: 0;
    right: 0;
}

Keep logical directions using flexbox (they correctly adapt to dir):

.bit-mdl-tst {
    align-items: flex-start;
    justify-content: flex-start;
}

This eliminates duplication and fixes RTL behavior for absolute directions.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/BlazorUI/Bit.BlazorUI.Extras/Components/ProModal/BitProModal.scss` around
lines 37 - 110, Duplicate positioning classes cause redundant rules and break
RTL: replace the absolute-direction classes (.bit-mdl-tlf, .bit-mdl-trg,
.bit-mdl-clf, .bit-mdl-crg, .bit-mdl-blf, .bit-mdl-brg) so they use explicit
positioning (top/left/top/right/bottom/left/bottom/right) instead of flexbox,
and keep the logical-direction classes (.bit-mdl-tst, .bit-mdl-ten,
.bit-mdl-cst, .bit-mdl-cen, .bit-mdl-bst, .bit-mdl-ben) using flexbox
(align-items/justify-content) to preserve RTL behavior; remove the duplicated
flexbox rules from the absolute classes and consolidate identical rules to avoid
repetition.
src/BlazorUI/Bit.BlazorUI/Extensions/IBitBlazorUIServiceCollectionExtensions.cs (1)

10-17: Consider documenting singleton usage constraints.

When trySingleton=true, BitModalService is registered as a singleton with a single _container field. If multiple BitModalContainer instances exist in the application, the last container to call InitContainer will become the active container, potentially causing persistent modals queued before that point to be rendered in an unexpected location.

Applications using trySingleton=true should ensure only one BitModalContainer exists, or document this behavior for developers.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@src/BlazorUI/Bit.BlazorUI/Extensions/IBitBlazorUIServiceCollectionExtensions.cs`
around lines 10 - 17, The BitModalService singleton registration (controlled by
trySingleton) uses a single _container and when multiple BitModalContainer
instances call InitContainer the last caller wins; update documentation to state
that if you pass trySingleton=true you must ensure only one BitModalContainer
exists (or explain the last-InitContainer-wins behavior and that scoped
registration avoids it), and add this note to the public API surface — e.g., XML
docs on IBitBlazorUIServiceCollectionExtensions.AddBitBlazorUI/BitModalService
registration method and/or the BitModalService class mentioning trySingleton,
InitContainer, and the expected constraint so developers are aware.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/BlazorUI/Bit.BlazorUI.Extras/Components/ProModal/BitProModal.ts`:
- Around line 6-12: The removal logic can miss the original drag handle if the
selector changed because unbinding resolves the drag element from the current
selector instead of the one that was originally bound; update the ProModal
drag-drop registration to save the concrete elements (or at least the
dragElement reference) inside ProModal._dragDropListeners[containerSelector]
when adding, and then in ProModal.removeDragDrop use that stored dragElement and
stored listener references to remove the pointerdown handler and any visual CSS
class before deleting the entry; apply the same change to the other removal site
(the block around the second occurrence at the 52-61 region) so unbinding always
uses the originally-bound element instead of querying the selector again.

In `@src/BlazorUI/Bit.BlazorUI/Components/Surfaces/Modal/BitModal.razor`:
- Around line 13-16: The markup reads component fields (AriaModal and
ShowOverlay) directly which bypasses overrides in ModalParameters after Merge;
update the template to use ModalParameters.AriaModal and
ModalParameters.ShowOverlay (and ensure GetRole() reads from ModalParameters or
add a GetRole(ModalParameters) overload) so aria-modal and role reflect
merged/overridden values from ModalParameters instead of the internal fields.

In `@src/BlazorUI/Bit.BlazorUI/Components/Surfaces/Modal/BitModalService.cs`:
- Line 135: The overlay click handler is always set to close the modal which
allows blocking modals to be dismissed; update the builder.AddComponentParameter
call that sets BitModal.OnOverlayClick (currently using
EventCallback.Factory.Create<MouseEventArgs>(modalReference, () =>
modalReference.Close())) to only wire that EventCallback when
modalParameters?.Blocking is false (or not true), and pass null/omit the
parameter when modalParameters?.Blocking is true so blocking modals cannot be
closed by clicking the overlay.

In
`@src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Surfaces/Modal/BitModalServiceDemo.razor`:
- Line 17: The example currently has the BitModalContainer commented out so
modals created via BitModalService will not render; either uncomment the
BitModalContainer line (restore the component invocation, e.g.,
BitModalContainer ModalParameters="@(new() { FullWidth = true })") so the demo
works, or add a brief explanatory note near the Show button/BitModalService
usage stating that consumers must include <BitModalContainer /> (or equivalent)
in their layout/root component to render modals; update references in this file
(BitModalContainer, BitModalService) accordingly so the demo is functional or
clearly documents the requirement.

---

Outside diff comments:
In `@src/BlazorUI/Bit.BlazorUI/Components/Surfaces/Dialog/BitDialog.ts`:
- Around line 59-65: removeDragDrop currently exits early if
document.querySelector(dragElementSelector) returns null, leaking the entry in
Dialog._dragDropListeners and leaving document listeners attached; instead,
always read Dialog._dragDropListeners[id] and, even when dragElement is null,
remove the stored document-level listeners (using the listener functions from
the listeners object) and then delete Dialog._dragDropListeners[id]; only skip
element-specific cleanup when dragElement is null. Apply the same fix to the
other branch/duplicate logic around lines 70-80 that also assumes the element
exists.

---

Nitpick comments:
In `@src/BlazorUI/Bit.BlazorUI.Extras/Components/ProModal/BitProModal.razor.cs`:
- Around line 246-285: Add brief clarifying comments inside OnAfterRenderAsync
around the _offsetTop and AbsolutePosition logic: comment why _offsetTop = 0 is
set before calling ToggleScroll (it's a guard for the case when AutoToggleScroll
is false and ToggleScroll will not recalc _offsetTop), and comment why
StyleBuilder.Reset() and StateHasChanged() are invoked only when
AbsolutePosition is true (to ensure the computed top-offset style, which
ToggleScroll may have updated, is applied after render). Reference the symbols
_offsetTop, ToggleScroll, AutoToggleScroll, AbsolutePosition,
StyleBuilder.Reset, and OnAfterRenderAsync when placing the comments.

In `@src/BlazorUI/Bit.BlazorUI.Extras/Components/ProModal/BitProModal.scss`:
- Around line 37-110: Duplicate positioning classes cause redundant rules and
break RTL: replace the absolute-direction classes (.bit-mdl-tlf, .bit-mdl-trg,
.bit-mdl-clf, .bit-mdl-crg, .bit-mdl-blf, .bit-mdl-brg) so they use explicit
positioning (top/left/top/right/bottom/left/bottom/right) instead of flexbox,
and keep the logical-direction classes (.bit-mdl-tst, .bit-mdl-ten,
.bit-mdl-cst, .bit-mdl-cen, .bit-mdl-bst, .bit-mdl-ben) using flexbox
(align-items/justify-content) to preserve RTL behavior; remove the duplicated
flexbox rules from the absolute classes and consolidate identical rules to avoid
repetition.

In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/ProModal/BitProModalClassStyles.cs`:
- Around line 3-34: The BitProModalClassStyles class lacks a Merge method so
derived properties (HeaderContainer, Header, CloseButton, CloseIcon, Body,
Footer) are not preserved when merging; add a static
Merge(BitProModalClassStyles? first, BitProModalClassStyles? second) that calls
BitModalClassStyles.Merge for base fields then merges each derived string
property (choose non-null/longer/concatenate as project convention) into the
result, ensuring the returned BitProModalClassStyles contains merged values for
Root/Overlay/Content plus HeaderContainer, Header, CloseButton, CloseIcon, Body,
and Footer.

In
`@src/BlazorUI/Bit.BlazorUI/Extensions/IBitBlazorUIServiceCollectionExtensions.cs`:
- Around line 10-17: The BitModalService singleton registration (controlled by
trySingleton) uses a single _container and when multiple BitModalContainer
instances call InitContainer the last caller wins; update documentation to state
that if you pass trySingleton=true you must ensure only one BitModalContainer
exists (or explain the last-InitContainer-wins behavior and that scoped
registration avoids it), and add this note to the public API surface — e.g., XML
docs on IBitBlazorUIServiceCollectionExtensions.AddBitBlazorUI/BitModalService
registration method and/or the BitModalService class mentioning trySingleton,
InitContainer, and the expected constraint so developers are aware.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: 73cadd8e-9ee2-4813-a90b-6bf437b7a48f

📥 Commits

Reviewing files that changed from the base of the PR and between 842111d and 85e28a3.

📒 Files selected for processing (39)
  • src/BlazorUI/Bit.BlazorUI.Extras/Components/ProModal/BitProModal.razor
  • src/BlazorUI/Bit.BlazorUI.Extras/Components/ProModal/BitProModal.razor.cs
  • src/BlazorUI/Bit.BlazorUI.Extras/Components/ProModal/BitProModal.scss
  • src/BlazorUI/Bit.BlazorUI.Extras/Components/ProModal/BitProModal.ts
  • src/BlazorUI/Bit.BlazorUI.Extras/Components/ProModal/BitProModalClassStyles.cs
  • src/BlazorUI/Bit.BlazorUI.Extras/Components/ProModal/BitProModalJsRuntimeExtensions.cs
  • src/BlazorUI/Bit.BlazorUI.Extras/Extensions/IBlazorUIExtrasServiceCollectionExtensions.cs
  • src/BlazorUI/Bit.BlazorUI.Extras/Styles/extra-components.scss
  • src/BlazorUI/Bit.BlazorUI/Components/Surfaces/Dialog/BitDialog.razor.cs
  • src/BlazorUI/Bit.BlazorUI/Components/Surfaces/Dialog/BitDialog.ts
  • src/BlazorUI/Bit.BlazorUI/Components/Surfaces/Dialog/BitDialogJsRuntimeExtensions.cs
  • src/BlazorUI/Bit.BlazorUI/Components/Surfaces/Modal/BitModal.razor
  • src/BlazorUI/Bit.BlazorUI/Components/Surfaces/Modal/BitModal.razor.cs
  • src/BlazorUI/Bit.BlazorUI/Components/Surfaces/Modal/BitModal.scss
  • src/BlazorUI/Bit.BlazorUI/Components/Surfaces/Modal/BitModalContainer.razor
  • src/BlazorUI/Bit.BlazorUI/Components/Surfaces/Modal/BitModalContainer.razor.cs
  • src/BlazorUI/Bit.BlazorUI/Components/Surfaces/Modal/BitModalJsRuntimeExtensions.cs
  • src/BlazorUI/Bit.BlazorUI/Components/Surfaces/Modal/BitModalParameters.cs
  • src/BlazorUI/Bit.BlazorUI/Components/Surfaces/Modal/BitModalReference.cs
  • src/BlazorUI/Bit.BlazorUI/Components/Surfaces/Modal/BitModalService.cs
  • src/BlazorUI/Bit.BlazorUI/Extensions/IBitBlazorUIServiceCollectionExtensions.cs
  • src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Extras/ModalService/BitModalServiceDemo.razor
  • src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Extras/ProModal/BitProModalDemo.razor
  • src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Extras/ProModal/BitProModalDemo.razor.cs
  • src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Extras/ProModal/BitProModalDemo.razor.scss
  • src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Surfaces/Modal/BitModalDemo.razor
  • src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Surfaces/Modal/BitModalDemo.razor.cs
  • src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Surfaces/Modal/BitModalServiceDemo.razor
  • src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Surfaces/Modal/BitModalServiceDemo.razor.cs
  • src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Surfaces/Modal/BitModalServiceDemo.razor.scss
  • src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Surfaces/Modal/ModalContent.razor
  • src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Home/ComponentsSection.razor
  • src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Shared/MainLayout.razor
  • src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Shared/MainLayout.razor.NavItems.cs
  • src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/compilerconfig.json
  • src/BlazorUI/Tests/Bit.BlazorUI.Tests/Components/Extras/ProModal/BitProModalTests.cs
  • src/BlazorUI/Tests/Bit.BlazorUI.Tests/Components/Surfaces/Modal/BitModalServiceTests.cs
  • src/BlazorUI/Tests/Bit.BlazorUI.Tests/Components/Surfaces/Modal/BitModalTests.cs
  • src/BlazorUI/Tests/Bit.BlazorUI.Tests/Components/Surfaces/Modal/TestModalContent.cs
💤 Files with no reviewable changes (4)
  • src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Extras/ModalService/BitModalServiceDemo.razor
  • src/BlazorUI/Bit.BlazorUI/Components/Surfaces/Modal/BitModalJsRuntimeExtensions.cs
  • src/BlazorUI/Bit.BlazorUI/Components/Surfaces/Modal/BitModalParameters.cs
  • src/BlazorUI/Bit.BlazorUI/Components/Surfaces/Modal/BitModal.scss

Comment thread src/BlazorUI/Bit.BlazorUI.Extras/Components/ProModal/BitProModal.ts Outdated
Comment thread src/BlazorUI/Bit.BlazorUI/Components/Surfaces/Modal/BitModal.razor
@msynk

msynk commented Jun 11, 2026

Copy link
Copy Markdown
Member Author

@coderabbitai re-review

@coderabbitai

coderabbitai Bot commented Jun 11, 2026

Copy link
Copy Markdown

@msynk: I'll re-review the PR now.

✅ Action performed

Full review finished.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 4

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Extensions/IBlazorUIExtrasServiceCollectionExtensions.cs`:
- Line 16: The call forwarding trySingleton into services.AddBitBlazorUIServices
must not cause JS/stateful core services to be singletons; update
AddBitBlazorUIServices so that BitThemeManager, BitPageVisibility and
BitModalService are always registered with a non-singleton lifetime (scoped or
transient) regardless of the trySingleton flag — e.g., use
services.AddScoped/AddTransient or TryAddScoped for BitThemeManager (depends on
IJSRuntime), BitPageVisibility (holds _isInitialized and _dotnetObj) and
BitModalService (holds _container and _persistentModalsQueue), and
remove/override any code path that registers these three as singletons when
trySingleton is true.

In
`@src/BlazorUI/Bit.BlazorUI/Extensions/IBitBlazorUIServiceCollectionExtensions.cs`:
- Line 11: Public API change: restore the original
AddBitBlazorUIServices(IServiceCollection) overload so precompiled consumers do
not get MissingMethodException; add a parameterless public extension method
AddBitBlazorUIServices(this IServiceCollection services) that simply forwards to
the new AddBitBlazorUIServices(this IServiceCollection services, bool
trySingleton) (e.g., call the two-arg overload with the appropriate default such
as false) so the new implementation stays in one place and binary compatibility
is preserved.

In
`@src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Extras/ProModal/BitProModalDemo.razor`:
- Line 473: The demo injects the Font Awesome stylesheet via CDN without SRI or
crossorigin in BitProModalDemo.razor; update the <link> include to either serve
a local bundled copy or add Subresource Integrity and crossorigin attributes
(compute and add the proper integrity hash for
https://cdnjs.cloudflare.com/ajax/libs/font-awesome/7.0.1/css/all.min.css and
include crossorigin="anonymous"), or move the secure, integrity-pinned/bundled
stylesheet reference into the app layout so the demo no longer performs an
unpinned runtime CDN injection.

In
`@src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Extras/ProModal/BitProModalDemo.razor.scss`:
- Line 23: The SCSS uses the `::deep` pseudo-element in
BitProModalDemo.razor.scss which triggers stylelint's
selector-pseudo-element-no-unknown rule; add the same local suppression used in
other component SCSS files by inserting a single-line comment `/*
stylelint-disable-next-line selector-pseudo-element-no-unknown */` immediately
above the `::deep {` selector so the linter ignores this known pseudo-element
usage.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: bc17cbe3-6d21-4820-91a6-6a1800606785

📥 Commits

Reviewing files that changed from the base of the PR and between f66f0fc and 93350ab.

📒 Files selected for processing (37)
  • src/BlazorUI/Bit.BlazorUI.Extras/Components/ProModal/BitProModal.razor
  • src/BlazorUI/Bit.BlazorUI.Extras/Components/ProModal/BitProModal.razor.cs
  • src/BlazorUI/Bit.BlazorUI.Extras/Components/ProModal/BitProModal.scss
  • src/BlazorUI/Bit.BlazorUI.Extras/Components/ProModal/BitProModalClassStyles.cs
  • src/BlazorUI/Bit.BlazorUI.Extras/Extensions/IBlazorUIExtrasServiceCollectionExtensions.cs
  • src/BlazorUI/Bit.BlazorUI.Extras/Styles/extra-components.scss
  • src/BlazorUI/Bit.BlazorUI/Components/Surfaces/Dialog/BitDialog.razor.cs
  • src/BlazorUI/Bit.BlazorUI/Components/Surfaces/Modal/BitModal.razor
  • src/BlazorUI/Bit.BlazorUI/Components/Surfaces/Modal/BitModal.razor.cs
  • src/BlazorUI/Bit.BlazorUI/Components/Surfaces/Modal/BitModal.scss
  • src/BlazorUI/Bit.BlazorUI/Components/Surfaces/Modal/BitModalContainer.razor
  • src/BlazorUI/Bit.BlazorUI/Components/Surfaces/Modal/BitModalContainer.razor.cs
  • src/BlazorUI/Bit.BlazorUI/Components/Surfaces/Modal/BitModalJsRuntimeExtensions.cs
  • src/BlazorUI/Bit.BlazorUI/Components/Surfaces/Modal/BitModalParameters.cs
  • src/BlazorUI/Bit.BlazorUI/Components/Surfaces/Modal/BitModalReference.cs
  • src/BlazorUI/Bit.BlazorUI/Components/Surfaces/Modal/BitModalService.cs
  • src/BlazorUI/Bit.BlazorUI/Extensions/IBitBlazorUIServiceCollectionExtensions.cs
  • src/BlazorUI/Bit.BlazorUI/Extensions/JsInterop/DragDropJsRuntimeExtensions.cs
  • src/BlazorUI/Bit.BlazorUI/Scripts/DragDrop.ts
  • src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Extras/ModalService/BitModalServiceDemo.razor
  • src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Extras/ProModal/BitProModalDemo.razor
  • src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Extras/ProModal/BitProModalDemo.razor.cs
  • src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Extras/ProModal/BitProModalDemo.razor.scss
  • src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Surfaces/Modal/BitModalDemo.razor
  • src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Surfaces/Modal/BitModalDemo.razor.cs
  • src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Surfaces/Modal/BitModalServiceDemo.razor
  • src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Surfaces/Modal/BitModalServiceDemo.razor.cs
  • src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Surfaces/Modal/BitModalServiceDemo.razor.scss
  • src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Surfaces/Modal/ModalContent.razor
  • src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Home/ComponentsSection.razor
  • src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Shared/MainLayout.razor
  • src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Shared/MainLayout.razor.NavItems.cs
  • src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/compilerconfig.json
  • src/BlazorUI/Tests/Bit.BlazorUI.Tests/Components/Extras/ProModal/BitProModalTests.cs
  • src/BlazorUI/Tests/Bit.BlazorUI.Tests/Components/Surfaces/Modal/BitModalServiceTests.cs
  • src/BlazorUI/Tests/Bit.BlazorUI.Tests/Components/Surfaces/Modal/BitModalTests.cs
  • src/BlazorUI/Tests/Bit.BlazorUI.Tests/Components/Surfaces/Modal/TestModalContent.cs
💤 Files with no reviewable changes (4)
  • src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Extras/ModalService/BitModalServiceDemo.razor
  • src/BlazorUI/Bit.BlazorUI/Components/Surfaces/Modal/BitModalJsRuntimeExtensions.cs
  • src/BlazorUI/Bit.BlazorUI/Components/Surfaces/Modal/BitModal.scss
  • src/BlazorUI/Bit.BlazorUI/Components/Surfaces/Modal/BitModalParameters.cs

Comment thread src/BlazorUI/Bit.BlazorUI/Extensions/IBitBlazorUIServiceCollectionExtensions.cs Outdated
@msynk

msynk commented Jun 12, 2026

Copy link
Copy Markdown
Member Author

@coderabbitait re-review

@coderabbitai

coderabbitai Bot commented Jun 12, 2026

Copy link
Copy Markdown

@msynk: It looks like there's a small typo — you tagged @coderabbitait instead of @coderabbitai. No worries, I'll go ahead and re-review the PR now!

✅ Action performed

Full review finished.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 5

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
src/BlazorUI/Bit.BlazorUI/Components/Surfaces/Modal/BitModal.razor.cs (1)

141-149: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Use the merged blocking flag in the overlay-dismiss path.

Line 147 checks Blocking instead of ModalParameters.Blocking, so blocking supplied through BitModalParameters.Merge(...) is ignored. Service-created blocking modals will still close on overlay click once execution reaches AssignIsOpen(false).

Suggested patch
-        if (Blocking) return;
+        if (ModalParameters.Blocking) return;
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/BlazorUI/Bit.BlazorUI/Components/Surfaces/Modal/BitModal.razor.cs` around
lines 141 - 149, HandleOnOverlayClick uses the local Blocking flag instead of
the merged setting on ModalParameters, so blocking provided via
BitModalParameters.Merge(...) is ignored; update the overlay-dismiss path in
HandleOnOverlayClick to check ModalParameters.Blocking (or the merged blocking
property on ModalParameters) instead of the local Blocking before calling
AssignIsOpen(false), keeping the existing early returns: preserve the
ModalParameters.IsEnabled check, await
ModalParameters.OnOverlayClick.InvokeAsync(e), then if
(ModalParameters.Blocking) return, then await AssignIsOpen(false).
♻️ Duplicate comments (1)
src/BlazorUI/Bit.BlazorUI.Extras/Extensions/IBlazorUIExtrasServiceCollectionExtensions.cs (1)

18-27: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Keep BitModalService scoped when trySingleton is true.

This branch still registers BitModalService as a singleton, so modal/container state can leak across Blazor circuits. The new base-service call fixes the earlier registration gap, but not this singleton-safety issue.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@src/BlazorUI/Bit.BlazorUI.Extras/Extensions/IBlazorUIExtrasServiceCollectionExtensions.cs`
around lines 18 - 27, The BitModalService should never be registered as a
singleton because its modal/container state can leak across Blazor circuits;
update the registration in IBlazorUIExtrasServiceCollectionExtensions so that
BitModalService is always registered scoped (use
services.TryAddScoped<BitModalService>() regardless of trySingleton), while
BitMessageBoxService may remain singleton when trySingleton is true; locate the
code paths that call services.TryAddSingleton<BitModalService>() and change them
to services.TryAddScoped<BitModalService>() (or ensure an unconditional
TryAddScoped registration for BitModalService) so modal state is circuit-scoped.
🧹 Nitpick comments (2)
src/BlazorUI/Tests/Bit.BlazorUI.Tests/Components/Extras/ProModal/BitProModalTests.cs (1)

27-50: ⚡ Quick win

Add a positive-path test for OnOverlayClick in non-blocking mode.

Current coverage proves the callback is suppressed when Blocking=true, but it doesn’t prove the callback fires when blocking is off. Adding that assertion closes a meaningful behavior gap.

Suggested test addition
+[TestMethod]
+public void BitProModalNonBlockingOverlayClickShouldInvokeOverlayCallback()
+{
+    var overlayClicked = 0;
+    var isOpen = true;
+
+    var com = RenderComponent<BitProModal>(parameters =>
+    {
+        parameters.Bind(p => p.IsOpen, isOpen, value => isOpen = value);
+        parameters.Add(p => p.Blocking, false);
+        parameters.Add(p => p.OnOverlayClick, EventCallback.Factory.Create<MouseEventArgs>(this, () => overlayClicked++));
+    });
+
+    com.Find(".bit-mdl-ovl").Click();
+
+    com.WaitForAssertion(() =>
+    {
+        Assert.AreEqual(1, overlayClicked);
+    });
+}
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@src/BlazorUI/Tests/Bit.BlazorUI.Tests/Components/Extras/ProModal/BitProModalTests.cs`
around lines 27 - 50, Add a new positive-path test (e.g.,
BitProModalOverlayClickShouldInvokeCallbackWhenNotBlocking) that renders
BitProModal with IsOpen=true, Blocking=false, and event handlers for
OnOverlayClick and OnDismiss that increment counters; simulate clicking the
overlay element (".bit-mdl-ovl") and assert that overlayClicked == 1 (and
optionally dismissed == 1 if dismiss-on-overlay is expected) and that IsOpen
changed to false and the modal role remains correct; use the same render pattern
and bindings as BitProModalBlockingShouldPreventOverlayDismissAndOverlayCallback
but set parameters.Add(p => p.Blocking, false) and adjust assertions to confirm
the overlay callback fires.
src/BlazorUI/Tests/Bit.BlazorUI.Tests/Components/Surfaces/Modal/BitModalTests.cs (1)

6-154: ⚡ Quick win

Add focused tests for ShowOverlay and AriaModal on BitModal.

Given the updated BitModal parameter surface, this suite should explicitly assert overlay presence/absence and aria-modal forwarding to prevent silent regressions.

Suggested test additions
+[TestMethod]
+public void BitModalShowOverlayFalseShouldNotRenderOverlay()
+{
+    var com = RenderComponent<BitModal>(parameters =>
+    {
+        parameters.Add(p => p.IsOpen, true);
+        parameters.Add(p => p.ShowOverlay, false);
+    });
+
+    Assert.AreEqual(0, com.FindAll(".bit-mdl-ovl").Count);
+}
+
+[TestMethod]
+public void BitModalAriaModalShouldBeForwarded()
+{
+    var com = RenderComponent<BitModal>(parameters =>
+    {
+        parameters.Add(p => p.IsOpen, true);
+        parameters.Add(p => p.AriaModal, false);
+    });
+
+    Assert.AreEqual("false", com.Find(".bit-mdl").Attributes["aria-modal"]?.Value);
+}
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@src/BlazorUI/Tests/Bit.BlazorUI.Tests/Components/Surfaces/Modal/BitModalTests.cs`
around lines 6 - 154, Add two focused tests to BitModalTests to verify the new
ShowOverlay and AriaModal behavior: create BitModalShowOverlayTest that renders
BitModal with IsOpen=true and toggles parameters.Add(p => p.ShowOverlay,
true/false) asserting presence (FindAll(".bit-mdl-ovl").Count == 1) when true
and absence (Count == 0) when false; and create BitModalAriaModalTest that
renders BitModal with IsOpen=true and parameters.Add(p => p.AriaModal,
true/false) then assert the modal element (Find(".bit-mdl")) has or does not
have the "aria-modal" attribute/value accordingly; reference existing helpers
RenderComponent<BitModal>, Find(".bit-mdl") and Find(".bit-mdl-ovl") and follow
the existing test patterns for parameter setup and assertions.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/BlazorUI/Bit.BlazorUI.Extras/Components/ProModal/BitProModal.razor.cs`:
- Around line 304-310: The current HandleOverlayClick method suppresses the
OnOverlayClick callback when Blocking is true; change the order so the method
still returns early if IsEnabled is false but always invokes await
OnOverlayClick.InvokeAsync(e) before checking Blocking, and only short-circuits
further processing after the callback if Blocking is true; update the
HandleOverlayClick method to call OnOverlayClick regardless of Blocking while
keeping the IsEnabled guard and existing blocking behavior for subsequent
actions.

In `@src/BlazorUI/Bit.BlazorUI.Extras/Styles/extra-components.scss`:
- Line 15: The SCSS import in extra-components.scss still includes the .scss
extension and triggers scss/load-partial-extension; update the import that
references BitProModal.scss by removing the “.scss” suffix so it imports the
partial (referencing the import statement that mentions BitProModal.scss) and
save the file to resolve the lint rule.

In `@src/BlazorUI/Bit.BlazorUI/Scripts/DragDrop.ts`:
- Around line 8-10: The drag handle lookup is using document.querySelector which
can pick a handle outside the intended container; change the lookup to scope it
to the found container by querying the container element (use
element.querySelector with the dragElementSelector) so dragElement is resolved
inside the matched container element (keep checks on element and dragElement as
before and update any related references in DragDrop.ts to use the scoped
dragElement).

In
`@src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Extras/ModalService/BitModalServiceDemo.razor.cs`:
- Around line 60-63: The Razor sample in the example1RazorCode string treats
ModalParameters as plain text; change the BitModalContainer attribute to bind an
instance by using Razor code syntax, e.g. replace ModalParameters="new() {
FullWidth = true }" with ModalParameters="`@new` BitModalParameters { FullWidth =
true }" (update the example1RazorCode string accordingly so the snippet compiles
and creates a BitModalParameters with FullWidth = true).

In
`@src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Extras/ProModal/BitProModalDemo.razor.cs`:
- Around line 586-592: The sample string example3CsharpCode is missing the
appShellContainer declaration referenced by ScrollerElement="appShellContainer",
so add a self-contained declaration (e.g., ElementReference appShellContainer =
default!;) inside the example3CsharpCode block alongside the other demo fields
(isBlockingProModalOpen, bitProModalRef, etc.) so the displayed C# snippet
compiles when copied.

---

Outside diff comments:
In `@src/BlazorUI/Bit.BlazorUI/Components/Surfaces/Modal/BitModal.razor.cs`:
- Around line 141-149: HandleOnOverlayClick uses the local Blocking flag instead
of the merged setting on ModalParameters, so blocking provided via
BitModalParameters.Merge(...) is ignored; update the overlay-dismiss path in
HandleOnOverlayClick to check ModalParameters.Blocking (or the merged blocking
property on ModalParameters) instead of the local Blocking before calling
AssignIsOpen(false), keeping the existing early returns: preserve the
ModalParameters.IsEnabled check, await
ModalParameters.OnOverlayClick.InvokeAsync(e), then if
(ModalParameters.Blocking) return, then await AssignIsOpen(false).

---

Duplicate comments:
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Extensions/IBlazorUIExtrasServiceCollectionExtensions.cs`:
- Around line 18-27: The BitModalService should never be registered as a
singleton because its modal/container state can leak across Blazor circuits;
update the registration in IBlazorUIExtrasServiceCollectionExtensions so that
BitModalService is always registered scoped (use
services.TryAddScoped<BitModalService>() regardless of trySingleton), while
BitMessageBoxService may remain singleton when trySingleton is true; locate the
code paths that call services.TryAddSingleton<BitModalService>() and change them
to services.TryAddScoped<BitModalService>() (or ensure an unconditional
TryAddScoped registration for BitModalService) so modal state is circuit-scoped.

---

Nitpick comments:
In
`@src/BlazorUI/Tests/Bit.BlazorUI.Tests/Components/Extras/ProModal/BitProModalTests.cs`:
- Around line 27-50: Add a new positive-path test (e.g.,
BitProModalOverlayClickShouldInvokeCallbackWhenNotBlocking) that renders
BitProModal with IsOpen=true, Blocking=false, and event handlers for
OnOverlayClick and OnDismiss that increment counters; simulate clicking the
overlay element (".bit-mdl-ovl") and assert that overlayClicked == 1 (and
optionally dismissed == 1 if dismiss-on-overlay is expected) and that IsOpen
changed to false and the modal role remains correct; use the same render pattern
and bindings as BitProModalBlockingShouldPreventOverlayDismissAndOverlayCallback
but set parameters.Add(p => p.Blocking, false) and adjust assertions to confirm
the overlay callback fires.

In
`@src/BlazorUI/Tests/Bit.BlazorUI.Tests/Components/Surfaces/Modal/BitModalTests.cs`:
- Around line 6-154: Add two focused tests to BitModalTests to verify the new
ShowOverlay and AriaModal behavior: create BitModalShowOverlayTest that renders
BitModal with IsOpen=true and toggles parameters.Add(p => p.ShowOverlay,
true/false) asserting presence (FindAll(".bit-mdl-ovl").Count == 1) when true
and absence (Count == 0) when false; and create BitModalAriaModalTest that
renders BitModal with IsOpen=true and parameters.Add(p => p.AriaModal,
true/false) then assert the modal element (Find(".bit-mdl")) has or does not
have the "aria-modal" attribute/value accordingly; reference existing helpers
RenderComponent<BitModal>, Find(".bit-mdl") and Find(".bit-mdl-ovl") and follow
the existing test patterns for parameter setup and assertions.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: cb606bc8-d463-4334-9c5b-d5f353cdce69

📥 Commits

Reviewing files that changed from the base of the PR and between f66f0fc and ced09f9.

📒 Files selected for processing (33)
  • src/BlazorUI/Bit.BlazorUI.Extras/Components/ModalService/BitModalContainer.razor
  • src/BlazorUI/Bit.BlazorUI.Extras/Components/ModalService/BitModalContainer.razor.cs
  • src/BlazorUI/Bit.BlazorUI.Extras/Components/ModalService/BitModalReference.cs
  • src/BlazorUI/Bit.BlazorUI.Extras/Components/ModalService/BitModalService.cs
  • src/BlazorUI/Bit.BlazorUI.Extras/Components/ProModal/BitProModal.razor
  • src/BlazorUI/Bit.BlazorUI.Extras/Components/ProModal/BitProModal.razor.cs
  • src/BlazorUI/Bit.BlazorUI.Extras/Components/ProModal/BitProModal.scss
  • src/BlazorUI/Bit.BlazorUI.Extras/Components/ProModal/BitProModalClassStyles.cs
  • src/BlazorUI/Bit.BlazorUI.Extras/Extensions/IBlazorUIExtrasServiceCollectionExtensions.cs
  • src/BlazorUI/Bit.BlazorUI.Extras/Styles/extra-components.scss
  • src/BlazorUI/Bit.BlazorUI/Components/Surfaces/Dialog/BitDialog.razor.cs
  • src/BlazorUI/Bit.BlazorUI/Components/Surfaces/Modal/BitModal.razor
  • src/BlazorUI/Bit.BlazorUI/Components/Surfaces/Modal/BitModal.razor.cs
  • src/BlazorUI/Bit.BlazorUI/Components/Surfaces/Modal/BitModal.scss
  • src/BlazorUI/Bit.BlazorUI/Components/Surfaces/Modal/BitModalJsRuntimeExtensions.cs
  • src/BlazorUI/Bit.BlazorUI/Components/Surfaces/Modal/BitModalParameters.cs
  • src/BlazorUI/Bit.BlazorUI/Extensions/IBitBlazorUIServiceCollectionExtensions.cs
  • src/BlazorUI/Bit.BlazorUI/Extensions/JsInterop/DragDropJsRuntimeExtensions.cs
  • src/BlazorUI/Bit.BlazorUI/Scripts/DragDrop.ts
  • src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Extras/ModalService/BitModalServiceDemo.razor
  • src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Extras/ModalService/BitModalServiceDemo.razor.cs
  • src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Extras/ProModal/BitProModalDemo.razor
  • src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Extras/ProModal/BitProModalDemo.razor.cs
  • src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Extras/ProModal/BitProModalDemo.razor.scss
  • src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Surfaces/Modal/BitModalDemo.razor
  • src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Surfaces/Modal/BitModalDemo.razor.cs
  • src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Home/ComponentsSection.razor
  • src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Shared/MainLayout.razor
  • src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Shared/MainLayout.razor.NavItems.cs
  • src/BlazorUI/Tests/Bit.BlazorUI.Tests/Components/Extras/ProModal/BitProModalTests.cs
  • src/BlazorUI/Tests/Bit.BlazorUI.Tests/Components/Surfaces/Modal/BitModalServiceTests.cs
  • src/BlazorUI/Tests/Bit.BlazorUI.Tests/Components/Surfaces/Modal/BitModalTests.cs
  • src/BlazorUI/Tests/Bit.BlazorUI.Tests/Components/Surfaces/Modal/TestModalContent.cs
💤 Files with no reviewable changes (3)
  • src/BlazorUI/Bit.BlazorUI/Components/Surfaces/Modal/BitModalJsRuntimeExtensions.cs
  • src/BlazorUI/Bit.BlazorUI/Components/Surfaces/Modal/BitModal.scss
  • src/BlazorUI/Bit.BlazorUI/Components/Surfaces/Modal/BitModalParameters.cs

Comment thread src/BlazorUI/Bit.BlazorUI.Extras/Styles/extra-components.scss
Comment thread src/BlazorUI/Bit.BlazorUI/Scripts/DragDrop.ts
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 BitProModal component is missing from the Extras project of the BlazorUI

1 participant