Skip to content

Enhance/storybook confirmation#47

Open
sapayth wants to merge 6 commits intogetdokan:mainfrom
sapayth:enhance/storybook_confirmation
Open

Enhance/storybook confirmation#47
sapayth wants to merge 6 commits intogetdokan:mainfrom
sapayth:enhance/storybook_confirmation

Conversation

@sapayth
Copy link
Collaborator

@sapayth sapayth commented Feb 9, 2026

add Confirmation components examples for the storybook

Summary by CodeRabbit

  • New Features

    • Added a reusable Confirmation dialog and Storybook examples.
    • New Modal demo for creating shipping zones.
    • Expanded Alert demos with icon, description and action variants.
    • Exposed a theming helper for computing theme styles.
  • Style

    • Adjusted Alert, Modal and Notice spacing and modal header/footer borders for improved layout.
  • Accessibility

    • Improved modal ARIA labeling, focus management and scroll lock for better keyboard and screen-reader behavior.

@coderabbitai
Copy link

coderabbitai bot commented Feb 9, 2026

📝 Walkthrough

Walkthrough

Adds a new Confirmation component and Storybook stories; modernizes Alert and Modal stories to args-based renders with additional variants; enhances Modal runtime behavior (focus trap, aria wiring, portal/theme handling) and styling tweaks (alert/notice padding, modal slot borders); exposes getThemeStyles helper.

Changes

Cohort / File(s) Summary
Stories — Alert / Modal / Confirmation
src/components/ui/Alert.stories.tsx, src/components/ui/Modal.stories.tsx, src/components/ui/Confirmation.stories.tsx
Converted Alert stories to args-based renders and added variants (WithDescription, WithButtons, etc.); added CreateShippingZone story to Modal; added new Confirmation.stories.tsx with multiple demo stories.
New Component: Confirmation
src/components/ui/confirmation.tsx, src/components/ui/index.ts
New exported Confirmation component plus ConfirmationProps and ConfirmationVariant types; renders a modal confirmation dialog with confirm/cancel handlers and visual variants; added public exports in UI barrel.
Modal runtime & API changes
src/components/ui/modal.tsx, src/styles.css
Introduced ModalContext for aria ids, focus-trap/tab handling, initial-focus behavior, portal container creation/cleanup, body scroll lock, data-state attributes, data-slot attributes for header/footer, role prop on ModalProps; added CSS rules for modal slot borders in src/styles.css.
Alert / Notice styling tweaks
src/components/ui/alert.tsx, src/components/ui/notice.tsx
Adjusted Alert padding (px-5p-5) and added internal AlertIcon mapping; removed w-full from Notice default classes.
Theme provider helper
src/providers/theme-provider.tsx, src/providers/index.ts
Added and re-exported getThemeStyles(tokens) that returns CSS variable map from ThemeTokens.
Minor / supporting
src/components/ui/alert.stories.tsx (imports), src/components/ui/Modal.stories.tsx (meta args)`
Export surface changes in stories (args + render usage); updated story metas to include default args like open/onClose.

Sequence Diagram(s)

sequenceDiagram
  participant User
  participant Storybook
  participant Confirmation
  participant Modal
  participant AppCallbacks

  User->>Storybook: click "Open Confirmation" (story UI)
  Storybook->>Confirmation: render with props (open=true)
  Confirmation->>Modal: open(modalProps)
  Modal->>Modal: trap focus, apply theme vars, lock body scroll
  User->>Modal: click "Confirm"
  Modal->>Confirmation: onConfirm()
  Confirmation->>AppCallbacks: invoke onConfirm callback
  Confirmation->>Modal: close()
  Modal->>Modal: release focus trap, restore scroll, cleanup portal
  Modal->>Storybook: closed state
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Suggested reviewers

  • mrabbani

Poem

🐰 I hopped through stories, tidy and bright,
Icons and modals all snug for the night.
Focus is trapped, and the portal’s in place,
Confirmations ready—swift, gentle grace.
A carrot for testing, a hop and a cheer!

🚥 Pre-merge checks | ✅ 1 | ❌ 2
❌ Failed checks (1 warning, 1 inconclusive)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 27.27% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
Title check ❓ Inconclusive The title partially captures the main intent of adding Confirmation component examples to Storybook, but it is vague and uses a non-descriptive convention (Enhance/storybook) that doesn't clearly convey what is being enhanced or added. Consider a more specific title like 'Add Confirmation component Storybook examples' or 'Create Storybook stories for Confirmation component' to clearly indicate the primary change.
✅ Passed checks (1 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.

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

✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

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
Copy link

coderabbitai bot commented Feb 9, 2026

Caution

Failed to replace (edit) comment. This is likely due to insufficient permissions or the comment being deleted.

Error details
{"name":"HttpError","status":500,"request":{"method":"PATCH","url":"https://api.github.com/repos/getdokan/plugin-ui/issues/comments/3872783184","headers":{"accept":"application/vnd.github.v3+json","user-agent":"octokit.js/0.0.0-development octokit-core.js/7.0.6 Node.js/24","authorization":"token [REDACTED]","content-type":"application/json; charset=utf-8"},"body":{"body":"<!-- This is an auto-generated comment: summarize by coderabbit.ai -->\n<!-- walkthrough_start -->\n\n<details>\n<summary>📝 Walkthrough</summary>\n\n## Walkthrough\n\nThese changes modernize Storybook stories for UI components (Alert, Modal, Confirmation) by adopting args-based render patterns, adding new story variants with more complex compositions, and making targeted styling adjustments to Modal, Notice, and Alert components using CSS utilities and semantic data attributes.\n\n## Changes\n\n|Cohort / File(s)|Summary|\n|---|---|\n|**Story Modernization** <br> `src/components/ui/Alert.stories.tsx`, `src/components/ui/Modal.stories.tsx`, `src/components/ui/Confirmation.stories.tsx`|Converted Alert stories to args-based render pattern with new variants (WithDescription, WithoutDescription, WithButtons, WithDescriptionAndButtons); added AlertIcon helper for variant-specific icons. Created new Confirmation.stories.tsx with three demo stories (LeaveWithUnsavedChanges, CancelSubscription, DiscardDraft). Added CreateShippingZone story to Modal with expanded form UI demo.|\n|**Component Styling** <br> `src/components/ui/alert.tsx`, `src/components/ui/modal.tsx`, `src/components/ui/notice.tsx`, `src/styles.css`|Modified Alert padding (px-5 to p-5). Added data-slot attributes to Modal header/footer; removed border-color utility from borders. Removed w-full from Notice. Added CSS rules for modal slot border colors (`#E9E9E9`).|\n\n## Estimated code review effort\n\n🎯 3 (Moderate) | ⏱️ ~22 minutes\n\n## Poem\n\n> 🐰 Stories evolve with args that dance,\n> Modal slots now sport semantic stance,\n> Alert icons bloom in every shade,\n> Confirmations ready—no delays made!\n> A polish here, a pattern there,\n> UI components beyond compare!\n\n</details>\n\n<!-- walkthrough_end -->\n\n\n<!-- pre_merge_checks_walkthrough_start -->\n\n<details>\n<summary>🚥 Pre-merge checks | ✅ 1 | ❌ 2</summary>\n\n<details>\n<summary>❌ Failed checks (2 warnings)</summary>\n\n|     Check name     | Status     | Explanation                                                                                                                                                                                                                                                                                | Resolution                                                                                                                                                                                                  |\n| :----------------: | :--------- | :----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | :---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |\n|     Title check    | ⚠️ Warning | The title 'Enhance/storybook confirmation' is partially related to the changeset but does not reflect the primary changes. While confirmation stories are added, the PR also includes substantial changes to Alert stories, Modal stories, and styling updates across multiple components. | Revise the title to better reflect the scope of changes, such as 'Enhance storybook with confirmation, alert, and modal stories' or focus on the most significant addition if narrowing scope is preferred. |\n| Docstring Coverage | ⚠️ Warning | Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%.                                                                                                                                                                                                       | Write docstrings for the functions missing them to satisfy the coverage threshold.                                                                                                                          |\n\n</details>\n<details>\n<summary>✅ Passed checks (1 passed)</summary>\n\n|     Check name    | Status   | Explanation                                                 |\n| :---------------: | :------- | :---------------------------------------------------------- |\n| Description Check | ✅ Passed | Check skipped - CodeRabbit’s high-level summary is enabled. |\n\n</details>\n\n<sub>✏️ Tip: You can configure your own custom pre-merge checks in the settings.</sub>\n\n</details>\n\n<!-- pre_merge_checks_walkthrough_end -->\n\n<!-- finishing_touch_checkbox_start -->\n\n<details>\n<summary>✨ Finishing touches</summary>\n\n- [ ] <!-- {\"checkboxId\": \"7962f53c-55bc-4827-bfbf-6a18da830691\"} --> 📝 Generate docstrings\n<details>\n<summary>🧪 Generate unit tests (beta)</summary>\n\n- [ ] <!-- {\"checkboxId\": \"f47ac10b-58cc-4372-a567-0e02b2c3d479\", \"radioGroupId\": \"utg-output-choice-group-unknown_comment_id\"} -->   Create PR with unit tests\n- [ ] <!-- {\"checkboxId\": \"07f1e7d6-8a8e-4e23-9900-8731c2c87f58\", \"radioGroupId\": \"utg-output-choice-group-unknown_comment_id\"} -->   Post copyable unit tests in a comment\n\n</details>\n\n</details>\n\n<!-- finishing_touch_checkbox_end -->\n\n<!-- tips_start -->\n\n---\n\nThanks for using [CodeRabbit](https://coderabbit.ai?utm_source=oss&utm_medium=github&utm_campaign=getdokan/plugin-ui&utm_content=47)! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.\n\n<details>\n<summary>❤️ Share</summary>\n\n- [X](https://twitter.com/intent/tweet?text=I%20just%20used%20%40coderabbitai%20for%20my%20code%20review%2C%20and%20it%27s%20fantastic%21%20It%27s%20free%20for%20OSS%20and%20offers%20a%20free%20trial%20for%20the%20proprietary%20code.%20Check%20it%20out%3A&url=https%3A//coderabbit.ai)\n- [Mastodon](https://mastodon.social/share?text=I%20just%20used%20%40coderabbitai%20for%20my%20code%20review%2C%20and%20it%27s%20fantastic%21%20It%27s%20free%20for%20OSS%20and%20offers%20a%20free%20trial%20for%20the%20proprietary%20code.%20Check%20it%20out%3A%20https%3A%2F%2Fcoderabbit.ai)\n- [Reddit](https://www.reddit.com/submit?title=Great%20tool%20for%20code%20review%20-%20CodeRabbit&text=I%20just%20used%20CodeRabbit%20for%20my%20code%20review%2C%20and%20it%27s%20fantastic%21%20It%27s%20free%20for%20OSS%20and%20offers%20a%20free%20trial%20for%20proprietary%20code.%20Check%20it%20out%3A%20https%3A//coderabbit.ai)\n- [LinkedIn](https://www.linkedin.com/sharing/share-offsite/?url=https%3A%2F%2Fcoderabbit.ai&mini=true&title=Great%20tool%20for%20code%20review%20-%20CodeRabbit&summary=I%20just%20used%20CodeRabbit%20for%20my%20code%20review%2C%20and%20it%27s%20fantastic%21%20It%27s%20free%20for%20OSS%20and%20offers%20a%20free%20trial%20for%20proprietary%20code)\n\n</details>\n\n<sub>Comment `@coderabbitai help` to get the list of available commands and usage tips.</sub>\n\n<!-- tips_end -->\n\n<!-- internal state start -->\n\n\n<!-- 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= -->\n\n<!-- internal state end -->"},"request":{"retryCount":3,"retries":3,"retryAfter":16}},"response":{"url":"https://api.github.com/repos/getdokan/plugin-ui/issues/comments/3872783184","status":500,"headers":{"access-control-allow-origin":"*","access-control-expose-headers":"ETag, Link, Location, Retry-After, X-GitHub-OTP, X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Used, X-RateLimit-Resource, X-RateLimit-Reset, X-OAuth-Scopes, X-Accepted-OAuth-Scopes, X-Poll-Interval, X-GitHub-Media-Type, X-GitHub-SSO, X-GitHub-Request-Id, Deprecation, Sunset","content-length":"0","content-security-policy":"default-src 'none'","content-type":"application/json; charset=utf-8","date":"Mon, 09 Feb 2026 16:33:13 GMT","referrer-policy":"origin-when-cross-origin, strict-origin-when-cross-origin","server":"github.com","strict-transport-security":"max-age=31536000; includeSubdomains; preload","vary":"Accept-Encoding, Accept, X-Requested-With","x-accepted-github-permissions":"issues=write; pull_requests=write","x-content-type-options":"nosniff","x-frame-options":"deny","x-github-api-version-selected":"2022-11-28","x-github-media-type":"github.v3; format=json","x-github-request-id":"283B:28DE83:10C0B3D:4834C80:698A0C48","x-ratelimit-limit":"11800","x-ratelimit-remaining":"11727","x-ratelimit-reset":"1770658083","x-ratelimit-resource":"core","x-ratelimit-used":"73","x-xss-protection":"0"},"data":""}}

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: 2

Caution

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

⚠️ Outside diff range comments (1)
src/components/ui/modal.tsx (1)

395-406: ⚠️ Potential issue | 🟡 Minor

Escape handler will close all stacked modals simultaneously.

The keydown listener is added on document, so if two modals are open at the same time, a single Escape press triggers onClose for both. Consider stopping propagation or checking if this modal is the topmost before closing.

🤖 Fix all issues with AI agents
In `@src/components/ui/confirmation.tsx`:
- Around line 86-92: The fallback ModalDescription currently renders only
whitespace when body is null, leaving aria-describedby pointing at an empty
element; update the component that renders ModalDescription (look for the
Confirmation dialog render where body and title are used) to either omit the
ModalDescription entirely when body is null (and ensure aria-describedby is not
set) or render a meaningful default (e.g., repeat the title text) instead of a
blank space; modify the logic around body and the aria-describedby prop so it
only references ModalDescription when it contains real content.

In `@src/components/ui/Modal.stories.tsx`:
- Line 97: The Countries field is displaying the wrong helper text: replace the
usage of ZONE_NAME_HELPER inside the FieldDescription for the Countries field
with the appropriate helper (e.g., COUNTRIES_HELPER) or remove the
FieldDescription entirely; locate the FieldDescription component instance that
currently renders ZONE_NAME_HELPER and update it to reference the correct
constant (or an inline string) so the Countries field shows relevant copy
instead of the zone-name helper.
🧹 Nitpick comments (4)
src/components/ui/Modal.stories.tsx (1)

81-96: Dropdown is display-only with no selection state.

The Countries dropdown renders static text ("Bangladesh, United States") and clicking items does nothing. While this is a Storybook demo, a minimal useState for selection would make the story more useful for demonstrating the component's interactive behavior, consistent with the restOfWorld toggle above.

src/components/ui/confirmation.tsx (1)

51-59: onClose() is called before onConfirm/onCancel callbacks.

This means the modal always closes immediately, before the consumer's callback runs. If a consumer needs to perform an async operation (e.g., API call) and keep the dialog open on failure, this ordering prevents that. Consider letting the consumer control closing, or at minimum document this behavior.

src/components/ui/modal.tsx (2)

408-440: Focus trap uses a stale list of focusable elements.

The focusable elements are queried once when the layout effect runs (on [portalContainer, open] changes). If modal content changes dynamically after mount (e.g., a loading spinner replaced by form fields), the Tab-trap will reference stale elements. Consider re-querying focusables inside the handleKeyDown callback instead.

Proposed fix: query focusables at Tab-time
   useLayoutEffect(() => {
     if (!portalContainer || !open) return;
 
     const container = contentRef.current;
     if (!container) return;
 
     const focusables = container.querySelectorAll<HTMLElement>(
       FOCUSABLE_SELECTOR,
     );
     const first = focusables[0];
-    const last = focusables[focusables.length - 1];
 
     (first ?? container).focus();
 
     const handleKeyDown = (e: KeyboardEvent) => {
       if (e.key !== "Tab") return;
 
+      const currentFocusables = container.querySelectorAll<HTMLElement>(
+        FOCUSABLE_SELECTOR,
+      );
+      const firstEl = currentFocusables[0];
+      const lastEl = currentFocusables[currentFocusables.length - 1];
+
       if (e.shiftKey) {
-        if (document.activeElement === first) {
+        if (document.activeElement === firstEl) {
           e.preventDefault();
-          last?.focus();
+          lastEl?.focus();
         }
       } else {
-        if (document.activeElement === last) {
+        if (document.activeElement === lastEl) {
           e.preventDefault();
-          first?.focus();
+          firstEl?.focus();
         }
       }
     };

297-297: Module-level bodyScrollLockCount may leak across tests.

Since this is a module-scoped variable, it persists across test cases. If a test fails mid-render or doesn't unmount properly, the count drifts and subsequent tests may see overflow: hidden stuck on document.body. Consider resetting it in a test helper or using a ref-based approach.

Comment on lines +86 to +92
{body != null ? (
<ModalDescription className="p-5 pt-0 text-muted-foreground">
{body}
</ModalDescription>
) : (
<ModalDescription className="sr-only"> </ModalDescription>
)}
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Screen-reader-only description contains only whitespace.

When body is not provided, the fallback ModalDescription with className="sr-only" contains just a space. This means aria-describedby points to an element with no meaningful content, which can confuse screen readers. Consider either omitting the description entirely (and not setting aria-describedby) or providing a sensible default like the title text repeated.

🤖 Prompt for AI Agents
In `@src/components/ui/confirmation.tsx` around lines 86 - 92, The fallback
ModalDescription currently renders only whitespace when body is null, leaving
aria-describedby pointing at an empty element; update the component that renders
ModalDescription (look for the Confirmation dialog render where body and title
are used) to either omit the ModalDescription entirely when body is null (and
ensure aria-describedby is not set) or render a meaningful default (e.g., repeat
the title text) instead of a blank space; modify the logic around body and the
aria-describedby prop so it only references ModalDescription when it contains
real content.

))}
</DropdownMenuContent>
</DropdownMenu>
<FieldDescription>{ZONE_NAME_HELPER}</FieldDescription>
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Copy-paste issue: wrong helper text for the Countries field.

ZONE_NAME_HELPER ("Give a meaningful name for your reference") is reused as the description for the Countries field, which doesn't make sense. This should have its own description or be omitted.

Proposed fix
-            <FieldDescription>{ZONE_NAME_HELPER}</FieldDescription>
+            <FieldDescription>Select the countries for this shipping zone</FieldDescription>
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
<FieldDescription>{ZONE_NAME_HELPER}</FieldDescription>
<FieldDescription>Select the countries for this shipping zone</FieldDescription>
🤖 Prompt for AI Agents
In `@src/components/ui/Modal.stories.tsx` at line 97, The Countries field is
displaying the wrong helper text: replace the usage of ZONE_NAME_HELPER inside
the FieldDescription for the Countries field with the appropriate helper (e.g.,
COUNTRIES_HELPER) or remove the FieldDescription entirely; locate the
FieldDescription component instance that currently renders ZONE_NAME_HELPER and
update it to reference the correct constant (or an inline string) so the
Countries field shows relevant copy instead of the zone-name helper.

@sapayth sapayth mentioned this pull request Feb 10, 2026
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.

1 participant