Skip to content

fix(system-rsc): correct slot detection in getSlots()#5848

Closed
ITBoomBKStudio wants to merge 3 commits into
heroui-inc:canaryfrom
ITBoomBKStudio:fix/getslots-logic
Closed

fix(system-rsc): correct slot detection in getSlots()#5848
ITBoomBKStudio wants to merge 3 commits into
heroui-inc:canaryfrom
ITBoomBKStudio:fix/getslots-logic

Conversation

@ITBoomBKStudio
Copy link
Copy Markdown

@ITBoomBKStudio ITBoomBKStudio commented Oct 24, 2025

📝 Description

Fixes incorrect slot detection in the getSlots() helper.

This PR corrects how slot keys are collected from the variants object.
The previous implementation iterated over variant values and sometimes extracted wrong keys (for example numeric indices from arrays), which caused invalid or missing slot names in the resulting slots map.
The new logic walks through each variant group and its configs, gathering slot keys from nested objects while safely ignoring non-object values.

Related to #5847 — follow-up improvement that complements the extendVariants typing fixes.

⛳️ Current behavior (updates)

• getSlots() may return incorrect or incomplete slot maps.
• compoundVariants often fail to apply classes when extending a component, because slot names do not match those of the base component.

🚀 New behavior

• Correctly extracts all slot keys from variant configurations, including base component slots.
• compoundVariants.class.{slot} now applies reliably.
• Ignores arrays, strings, and non-plain objects to avoid noise.

💣 Is this a breaking change (Yes/No):

No.

📝 Additional Information

• Keeps compatibility with existing variant definitions.
• Tested with components that extend base slots (value, trigger, label, input, base, etc.).
• Complements the type-level PR #5847 which addressed CompoundVariants inference.

Summary by CodeRabbit

  • Refactor

    • Improved internal variant-processing to be safer and more predictable when extracting slot keys.
    • Strengthened input validation and guarded traversal to ignore malformed values and return an empty result for invalid input.
    • Ensured missing slot entries are initialized consistently; no changes to public APIs or outward behavior.
  • Chores

    • Added a changeset entry marking a minor package release.

@vercel
Copy link
Copy Markdown

vercel Bot commented Oct 24, 2025

@ITBoomBKStudio is attempting to deploy a commit to the HeroUI Inc Team on Vercel.

A member of the Team first needs to authorize it.

@changeset-bot
Copy link
Copy Markdown

changeset-bot Bot commented Oct 24, 2025

🦋 Changeset detected

Latest commit: c878267

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 37 packages
Name Type
@heroui/system-rsc Minor
@heroui/code Patch
@heroui/divider Patch
@heroui/kbd Patch
@heroui/spacer Patch
@heroui/spinner Patch
@heroui/system Patch
@heroui/react Patch
@heroui/accordion Patch
@heroui/listbox Patch
@heroui/menu Patch
@heroui/table Patch
@heroui/button Patch
@heroui/select Patch
@heroui/toast Patch
@heroui/alert Patch
@heroui/autocomplete Patch
@heroui/calendar Patch
@heroui/checkbox Patch
@heroui/date-input Patch
@heroui/date-picker Patch
@heroui/drawer Patch
@heroui/dropdown Patch
@heroui/form Patch
@heroui/input-otp Patch
@heroui/input Patch
@heroui/modal Patch
@heroui/navbar Patch
@heroui/number-input Patch
@heroui/popover Patch
@heroui/radio Patch
@heroui/slider Patch
@heroui/snippet Patch
@heroui/tabs Patch
@heroui/tooltip Patch
@heroui/aria-utils Patch
@heroui/framer-utils Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Oct 24, 2025

Walkthrough

Refactors getSlots(variants) to a guarded, multi-level traversal with explicit input validation, using a null-prototype accumulator and stricter type checks to collect unique slot names and initialize missing slots; returns {} for invalid input. Public API unchanged.

Changes

Cohort / File(s) Summary
getSlots function refactor
packages/core/system-rsc/src/extend-variants.js
Replaced permissive flatten/reduce with explicit nested traversal (variants → groups → configs → slot names); added guards rejecting non-plain objects, arrays, and String objects; uses a null-prototype accumulator; initializes missing slots to ""; returns {} on invalid input.
changeset
.changeset/four-guests-sneeze.md
Added changeset documenting the fix to getSlots() and a minor version bump for @heroui/system-rsc.

Sequence Diagram(s)

sequenceDiagram
    autonumber
    participant C as Caller
    participant S as getSlots(variants)
    participant V as variants (input)
    Note over S: Validation & guarded traversal
    C->>S: call getSlots(variants)
    S->>V: validate input type
    alt invalid
        S-->>C: return {}
    else valid
        S->>S: iterate variant groups
        S->>S: iterate configs
        S->>S: extract slot names, ignore non-plain objects/arrays/String objects
        S->>S: collect unique keys into null-prototype object, init missing to ""
        S-->>C: return slots object
    end
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

  • Check type-guard correctness (plain object detection vs arrays/String objects).
  • Verify null-prototype accumulator usage and downstream consumer compatibility.
  • Run representative inputs to confirm behavior matches previous implementation for compoundVariants.

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 50.00% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (2 passed)
Check name Status Explanation
Title Check ✅ Passed The title "fix(system-rsc): correct slot detection in getSlots()" directly corresponds to the primary change in the pull request. The raw summary confirms that the core change is a refactoring of getSlots(variants) to fix how slot keys are collected from the variants object, resolving issues with incorrect slot extraction. The title is concise, specific, and avoids vague language or noise. A developer scanning the commit history would immediately understand that this PR addresses a bug fix in the slot detection logic of the getSlots() function.
Description Check ✅ Passed The pull request description covers all critical sections of the template with substantial content: a clear description of the fix, a detailed current behavior section explaining the problems (incorrect slot extraction, compoundVariants failures), a comprehensive new behavior section describing the improvements, an explicit statement that this is not a breaking change, and additional context about compatibility and testing. The only missing element is the optional "Closes #" reference at the top, which is non-critical. The description follows the template structure, provides context about related work (PR #5847), and explains the impact of the changes, making it mostly complete and well-organized.
✨ Finishing touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

📜 Recent review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 0293552 and c878267.

📒 Files selected for processing (1)
  • .changeset/four-guests-sneeze.md (1 hunks)
🔇 Additional comments (2)
.changeset/four-guests-sneeze.md (2)

1-3: Verify version bump level is appropriate.

The changeset specifies a "minor" version bump. According to semantic versioning, bug fixes typically warrant a "patch" bump, while "minor" is reserved for new features (backwards compatible). Since the PR title indicates this is a fix, please confirm whether "minor" is intentional or if "patch" is more appropriate.


5-5: Changelog message is clear and well-scoped.

The description accurately reflects the change scope, references the affected function and feature area, and aligns with the PR objectives.


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.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

🧹 Nitpick comments (1)
packages/core/system-rsc/src/extend-variants.js (1)

7-34: Well-structured refactoring that fixes the array indexing issue.

The explicit multi-level traversal with type guards correctly prevents numeric array indices from being extracted as slot names. The null-prototype accumulator and defensive hasOwnProperty check provide good protection against prototype pollution. The logic properly handles edge cases (null/undefined groups, arrays, String objects).

Consider adding a brief JSDoc comment explaining the expected variants structure and why String objects are explicitly checked:

+/**
+ * Extracts slot names from variant configurations.
+ * Traverses: variants -> variant groups -> variant configs -> slot names
+ * @param {Object} variants - Nested object: { variantName: { value: { slotName: "...", ... } } }
+ * @returns {Object} Map of slot names to empty strings
+ */
 function getSlots(variants) {
   if (!variants || typeof variants !== "object") return {};
 
   const acc = Object.create(null);
 
   for (const group of Object.values(variants)) {
     if (!group || typeof group !== "object") continue;
 
     for (const config of Object.values(group)) {
+      // Skip non-objects, arrays (which would yield numeric indices), and String objects
       if (
         !config ||
         typeof config !== "object" ||
         Array.isArray(config) ||
         config instanceof String
       ) {
         continue;
       }
📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 328c57d and 2dfa44c.

📒 Files selected for processing (1)
  • packages/core/system-rsc/src/extend-variants.js (1 hunks)

@pkg-pr-new
Copy link
Copy Markdown

pkg-pr-new Bot commented Oct 25, 2025

Open in StackBlitz

@heroui/accordion

npm i https://pkg.pr.new/@heroui/accordion@5848

@heroui/alert

npm i https://pkg.pr.new/@heroui/alert@5848

@heroui/autocomplete

npm i https://pkg.pr.new/@heroui/autocomplete@5848

@heroui/avatar

npm i https://pkg.pr.new/@heroui/avatar@5848

@heroui/badge

npm i https://pkg.pr.new/@heroui/badge@5848

@heroui/breadcrumbs

npm i https://pkg.pr.new/@heroui/breadcrumbs@5848

@heroui/button

npm i https://pkg.pr.new/@heroui/button@5848

@heroui/calendar

npm i https://pkg.pr.new/@heroui/calendar@5848

@heroui/card

npm i https://pkg.pr.new/@heroui/card@5848

@heroui/checkbox

npm i https://pkg.pr.new/@heroui/checkbox@5848

@heroui/chip

npm i https://pkg.pr.new/@heroui/chip@5848

@heroui/code

npm i https://pkg.pr.new/@heroui/code@5848

@heroui/date-input

npm i https://pkg.pr.new/@heroui/date-input@5848

@heroui/date-picker

npm i https://pkg.pr.new/@heroui/date-picker@5848

@heroui/divider

npm i https://pkg.pr.new/@heroui/divider@5848

@heroui/drawer

npm i https://pkg.pr.new/@heroui/drawer@5848

@heroui/dropdown

npm i https://pkg.pr.new/@heroui/dropdown@5848

@heroui/form

npm i https://pkg.pr.new/@heroui/form@5848

@heroui/image

npm i https://pkg.pr.new/@heroui/image@5848

@heroui/input

npm i https://pkg.pr.new/@heroui/input@5848

@heroui/input-otp

npm i https://pkg.pr.new/@heroui/input-otp@5848

@heroui/kbd

npm i https://pkg.pr.new/@heroui/kbd@5848

@heroui/link

npm i https://pkg.pr.new/@heroui/link@5848

@heroui/listbox

npm i https://pkg.pr.new/@heroui/listbox@5848

@heroui/menu

npm i https://pkg.pr.new/@heroui/menu@5848

@heroui/modal

npm i https://pkg.pr.new/@heroui/modal@5848

@heroui/navbar

npm i https://pkg.pr.new/@heroui/navbar@5848

@heroui/number-input

npm i https://pkg.pr.new/@heroui/number-input@5848

@heroui/pagination

npm i https://pkg.pr.new/@heroui/pagination@5848

@heroui/popover

npm i https://pkg.pr.new/@heroui/popover@5848

@heroui/progress

npm i https://pkg.pr.new/@heroui/progress@5848

@heroui/radio

npm i https://pkg.pr.new/@heroui/radio@5848

@heroui/ripple

npm i https://pkg.pr.new/@heroui/ripple@5848

@heroui/scroll-shadow

npm i https://pkg.pr.new/@heroui/scroll-shadow@5848

@heroui/select

npm i https://pkg.pr.new/@heroui/select@5848

@heroui/skeleton

npm i https://pkg.pr.new/@heroui/skeleton@5848

@heroui/slider

npm i https://pkg.pr.new/@heroui/slider@5848

@heroui/snippet

npm i https://pkg.pr.new/@heroui/snippet@5848

@heroui/spacer

npm i https://pkg.pr.new/@heroui/spacer@5848

@heroui/spinner

npm i https://pkg.pr.new/@heroui/spinner@5848

@heroui/switch

npm i https://pkg.pr.new/@heroui/switch@5848

@heroui/table

npm i https://pkg.pr.new/@heroui/table@5848

@heroui/tabs

npm i https://pkg.pr.new/@heroui/tabs@5848

@heroui/toast

npm i https://pkg.pr.new/@heroui/toast@5848

@heroui/tooltip

npm i https://pkg.pr.new/@heroui/tooltip@5848

@heroui/user

npm i https://pkg.pr.new/@heroui/user@5848

@heroui/react

npm i https://pkg.pr.new/@heroui/react@5848

@heroui/system

npm i https://pkg.pr.new/@heroui/system@5848

@heroui/system-rsc

npm i https://pkg.pr.new/@heroui/system-rsc@5848

@heroui/theme

npm i https://pkg.pr.new/@heroui/theme@5848

@heroui/use-aria-accordion

npm i https://pkg.pr.new/@heroui/use-aria-accordion@5848

@heroui/use-aria-accordion-item

npm i https://pkg.pr.new/@heroui/use-aria-accordion-item@5848

@heroui/use-aria-button

npm i https://pkg.pr.new/@heroui/use-aria-button@5848

@heroui/use-aria-link

npm i https://pkg.pr.new/@heroui/use-aria-link@5848

@heroui/use-aria-modal-overlay

npm i https://pkg.pr.new/@heroui/use-aria-modal-overlay@5848

@heroui/use-aria-multiselect

npm i https://pkg.pr.new/@heroui/use-aria-multiselect@5848

@heroui/use-aria-overlay

npm i https://pkg.pr.new/@heroui/use-aria-overlay@5848

@heroui/use-callback-ref

npm i https://pkg.pr.new/@heroui/use-callback-ref@5848

@heroui/use-clipboard

npm i https://pkg.pr.new/@heroui/use-clipboard@5848

@heroui/use-data-scroll-overflow

npm i https://pkg.pr.new/@heroui/use-data-scroll-overflow@5848

@heroui/use-disclosure

npm i https://pkg.pr.new/@heroui/use-disclosure@5848

@heroui/use-draggable

npm i https://pkg.pr.new/@heroui/use-draggable@5848

@heroui/use-form-reset

npm i https://pkg.pr.new/@heroui/use-form-reset@5848

@heroui/use-image

npm i https://pkg.pr.new/@heroui/use-image@5848

@heroui/use-infinite-scroll

npm i https://pkg.pr.new/@heroui/use-infinite-scroll@5848

@heroui/use-intersection-observer

npm i https://pkg.pr.new/@heroui/use-intersection-observer@5848

@heroui/use-is-mobile

npm i https://pkg.pr.new/@heroui/use-is-mobile@5848

@heroui/use-is-mounted

npm i https://pkg.pr.new/@heroui/use-is-mounted@5848

@heroui/use-measure

npm i https://pkg.pr.new/@heroui/use-measure@5848

@heroui/use-pagination

npm i https://pkg.pr.new/@heroui/use-pagination@5848

@heroui/use-real-shape

npm i https://pkg.pr.new/@heroui/use-real-shape@5848

@heroui/use-ref-state

npm i https://pkg.pr.new/@heroui/use-ref-state@5848

@heroui/use-resize

npm i https://pkg.pr.new/@heroui/use-resize@5848

@heroui/use-safe-layout-effect

npm i https://pkg.pr.new/@heroui/use-safe-layout-effect@5848

@heroui/use-scroll-position

npm i https://pkg.pr.new/@heroui/use-scroll-position@5848

@heroui/use-ssr

npm i https://pkg.pr.new/@heroui/use-ssr@5848

@heroui/use-theme

npm i https://pkg.pr.new/@heroui/use-theme@5848

@heroui/use-update-effect

npm i https://pkg.pr.new/@heroui/use-update-effect@5848

@heroui/use-viewport-size

npm i https://pkg.pr.new/@heroui/use-viewport-size@5848

@heroui/aria-utils

npm i https://pkg.pr.new/@heroui/aria-utils@5848

@heroui/dom-animation

npm i https://pkg.pr.new/@heroui/dom-animation@5848

@heroui/framer-utils

npm i https://pkg.pr.new/@heroui/framer-utils@5848

@heroui/react-rsc-utils

npm i https://pkg.pr.new/@heroui/react-rsc-utils@5848

@heroui/react-utils

npm i https://pkg.pr.new/@heroui/react-utils@5848

@heroui/shared-icons

npm i https://pkg.pr.new/@heroui/shared-icons@5848

@heroui/shared-utils

npm i https://pkg.pr.new/@heroui/shared-utils@5848

@heroui/stories-utils

npm i https://pkg.pr.new/@heroui/stories-utils@5848

@heroui/test-utils

npm i https://pkg.pr.new/@heroui/test-utils@5848

commit: c878267

@wingkwong
Copy link
Copy Markdown
Member

As mentioned in #5847 please merge the changes to the linked PR. Also please include some test cases and examples in your description (i.e. before & after). Thanks.

@wingkwong wingkwong closed this Nov 3, 2025
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.

2 participants