fix(system-rsc): extendVariants rendering behavior with as#6215
Conversation
🦋 Changeset detectedLatest commit: 3c0c1a2 The changes in this PR will be included in the next version bump. This PR includes changesets to release 37 packages
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 |
|
@ITBoomBKStudio is attempting to deploy a commit to the HeroUI Inc Team on Vercel. A member of the Team first needs to authorize it. |
|
@wingkwong please check |
@heroui/accordion
@heroui/alert
@heroui/autocomplete
@heroui/avatar
@heroui/badge
@heroui/breadcrumbs
@heroui/button
@heroui/calendar
@heroui/card
@heroui/checkbox
@heroui/chip
@heroui/code
@heroui/date-input
@heroui/date-picker
@heroui/divider
@heroui/drawer
@heroui/dropdown
@heroui/form
@heroui/image
@heroui/input
@heroui/input-otp
@heroui/kbd
@heroui/link
@heroui/listbox
@heroui/menu
@heroui/modal
@heroui/navbar
@heroui/number-input
@heroui/pagination
@heroui/popover
@heroui/progress
@heroui/radio
@heroui/ripple
@heroui/scroll-shadow
@heroui/select
@heroui/skeleton
@heroui/slider
@heroui/snippet
@heroui/spacer
@heroui/spinner
@heroui/switch
@heroui/table
@heroui/tabs
@heroui/toast
@heroui/tooltip
@heroui/user
@heroui/react
@heroui/system
@heroui/system-rsc
@heroui/theme
@heroui/use-aria-accordion
@heroui/use-aria-accordion-item
@heroui/use-aria-button
@heroui/use-aria-link
@heroui/use-aria-modal-overlay
@heroui/use-aria-multiselect
@heroui/use-aria-overlay
@heroui/use-callback-ref
@heroui/use-clipboard
@heroui/use-data-scroll-overflow
@heroui/use-disclosure
@heroui/use-draggable
@heroui/use-form-reset
@heroui/use-image
@heroui/use-infinite-scroll
@heroui/use-intersection-observer
@heroui/use-is-mobile
@heroui/use-is-mounted
@heroui/use-measure
@heroui/use-pagination
@heroui/use-real-shape
@heroui/use-ref-state
@heroui/use-resize
@heroui/use-safe-layout-effect
@heroui/use-scroll-position
@heroui/use-ssr
@heroui/use-theme
@heroui/use-update-effect
@heroui/use-viewport-size
@heroui/aria-utils
@heroui/dom-animation
@heroui/framer-utils
@heroui/react-rsc-utils
@heroui/react-utils
@heroui/shared-icons
@heroui/shared-utils
@heroui/stories-utils
@heroui/test-utils
commit: |
|
Hey @jrgarciadev and @wingkwong 👋 I ran into a confusing inconsistency with Depending on how the
Below are the two versions that demonstrate the issue. Version that works in productionconst ForwardedComponent = React.forwardRef((originalProps = {}, ref) => {
const newProps = React.useMemo(
() =>
getClassNamesWithProps(
{
slots,
variants,
compoundVariants,
props: originalProps,
defaultVariants,
hasSlots,
opts,
},
[originalProps],
),
[originalProps],
);
return React.createElement(BaseComponent, {
...originalProps,
...newProps,
ref,
});
});Version that works in Jest testsconst ForwardedComponent = React.forwardRef((originalProps = {}, ref) => {
// Extract `as` prop if present
const { as: Component = BaseComponent, ...restProps } = originalProps;
const newProps = React.useMemo(
() =>
getClassNamesWithProps(
{
slots,
variants,
compoundVariants,
props: restProps,
defaultVariants,
hasSlots,
opts,
},
[restProps],
),
[restProps],
);
return React.createElement(Component, {
...restProps,
...newProps,
ref,
});
});In the second version, components render as the value passed to as instead of rendering as the original base component, which causes styling and rendering issues in production. This PR restores consistent rendering behavior by ensuring components created with extendVariants always render as the original base component, while still allowing as to be used in the styling logic. |
SummaryI’ve completely rewritten the test file to better reflect the actual behavior and responsibilities of In the process, I also fixed a serious issue with chained As a result, production behavior and test expectations are now aligned and predictable. Some additional cleanup may still be needed in related files, but the core logic and tests are now in a good and stable state. |
|
@jrgarciadev @wingkwong At the moment, this issue causes broken behavior in one of my projects, and having this fix available sooner would help a lot. |
* fix(theme): hide password reveal button (#5990) * fix(link): link overriding role (#5999) * fix(link): allow overriding role * chore(link): changeset * chore(deps): upgrade react-aria (v1.14.0) (#5996) * chore(deps): upgrade react-aria (v1.14.0) * refactor(react): group client components * fix(dropdown): keyDown test cases * chore(react): rollback * fix(theme): default transition-duration (#6011) * fix(theme): default transitionDuration * chore(deps): bump @heroui/theme peer dep * ci(changesets): version packages (#5991) Co-authored-by: Junior Garcia <jrgarciadev@gmail.com> * fix(use-image): resolve race condition with cached images on Firefox/Safari (#6041) * fix(use-image): resolve race condition with cached images on Firefox/Safari The bug occurred because event handlers (onload/onerror) were attached AFTER setting the image src. For cached images, browsers fire onload synchronously when src is set, causing the event to be missed and images to remain stuck at opacity-0. Changes: - Attach handlers BEFORE setting src to catch synchronous callbacks - Check both naturalWidth AND naturalHeight (per CodeRabbit review on #4523) - Handle synchronous error callbacks for failed cached images - Add comprehensive test coverage (15 tests) including: - Synchronous cached image success (Firefox/Safari race condition) - Synchronous cached image error - Dynamic src changes - All props (crossOrigin, srcSet, sizes, loading) - Callback invocation verification Reproduction and investigation performed using Claude Opus 4.5. Fixes #4534, #2259 * fix(use-image): add ignoreFallback to useCallback dependencies Address CodeRabbit review feedback: the `ignoreFallback` prop was used inside the `load` callback (line 104) but was missing from the dependency array, creating a stale closure bug. Without this fix, if `ignoreFallback` changes from `true` to `false` dynamically, the `load` callback would retain the stale `true` value, preventing the image from ever loading. Changes: - Add `ignoreFallback` to useCallback dependency array - Add tests for dynamic `ignoreFallback` changes (both directions) - Update changeset to document this fix Verification performed using Claude Opus 4.5. --------- Co-authored-by: Brian Meek <brian@current.space> * fix(docs): broken links in Form page (#6077) * fix(pagination): improve layout for large page counts (#6034) * fix(pagination): improve layout for large page counts/style of paagination compnents * fix(pagination): refine item sizing to balance small and large page numbers * ci(changesets): add pagination sizing changeset * fix(pagination): ensure cursor fully covers button without changing radius * chore(changeset): revise message and add issue numbers --------- Co-authored-by: WK Wong <wingkwong.code@gmail.com> * fix(date-picker): open date-picker when clicking border (#6084) * fix(date-picker): add pointer interaction to open date picker on wrapper click * chore: add changeset * chore(changeset): add issue number --------- Co-authored-by: WK <wingkwong.code@gmail.com> * fix(accordion): click behaviour for dynamically generated accordion items (#6133) * fix(accordion): add collection state * chore: add changeset * fix: update change set * refactor(theme): remove flat dependency (#6157) * chore(deps): remove flat library * refactor(theme): replace flatten from flat * chore: add changeset * fix(listbox): prevent option focus from start/end content slots (#6060) * fix(listbox): prevent option focus from start/end content slots * test: add test code about when clicking non-interactive slot content, and prevented focus leakage from interactive start/end content such as buttons. * docs: add changeset * chore(changeset): add issue number --------- Co-authored-by: WK <wingkwong.code@gmail.com> * fix(system-rsc): extendVariants & compound variants types (#5847) * fix(extendVariants): return component type error * fix(CompoundVariants): correct type inference for extended/compound variants and composition * test: cover compound/extend inference; enforce CP required props * fix(types): correct CompoundVariants class value inference Replaces the conditional ClassProp logic with a simpler, consistent form to fix incorrect slot value inference. Before: ClassProp<S extends undefined ? ClassValue : ClassValue | SlotsClassValue<S>> After: ClassProp<ClassValue | GetSuggestedValues<S>> This ensures GetSuggestedValues<S> is used for slot-aware variants and avoids duplicated conditional branches for undefined slots. * fix(system-rsc): correct slot detection in getSlots() * fix(types): make ExtendVariants props optional and guard V[key] with NonNullable Simplifies the return type of ExtendVariants to ensure no required props are enforced at the HOC level. This aligns with the intended API contract where extended components expose all props as optional. - All keys (CP ∪ V) are optional - Preserve CP type hints and booleanized V values - Added NonNullable<V[key]> guard to prevent undefined indexing * test(extendVariants): add compoundVariants integration test * fix(system-rsc): getSlots() brief JSDoc comment added * test(extendVariants): new styles - extended & fixed styles - original tests for slots component * test(extendVariants): fixed slot component variant styles extended test * fix(types): avoid leaking React internals by removing PropsWithoutRef Replace PropsWithoutRef with explicit Exclude<'ref'> in mapped keys and intersect with RefAttributes<InferRef<C>>. This prevents @types/react’s internal UNDEFINED_VOID_ONLY from leaking into the public .d.ts and fixes declaration emit for components like extended Autocomplete. * chore(changeset): add patch for extendVariants and CompoundVariants type fix * chore(system-rsc): add changeset for getSlots() slot detection fix * refactor(types): unify slot value inference via GetSuggestedValues<S> for consistent variant typing * fix(extendVariants): improved as-prop handling and exclude classNames from SuggestedVariants * fix(system-rsc): add polymorphic 'as' prop support to extendVariants * chore(system-rsc): add missing tests --------- Co-authored-by: doki- <1335902682@qq.com> Co-authored-by: WK Wong <wingkwong.code@gmail.com> * chore(docs): update meta (#6168) * ci(changesets): version packages (#6059) Co-authored-by: Junior Garcia <jrgarciadev@gmail.com> * fix(system-rsc): extendVariants rendering behavior with as (#6215) * fix(system-rsc): fix components rendering with 'as' prop * fix(system-rsc): fix compoundVariants and slots inheritance in extendVariants * fix(system-rsc): extendVariants test file cleaned * chore(deps): bump RA dependencies (#6221) * chore(deps): bump RA dependencies * chore(date-picker): revise test cases * fix(button): correct disableRipple prop precedence (#6199) * ci(changesets): version packages (#6227) Co-authored-by: Junior Garcia <jrgarciadev@gmail.com> --------- Co-authored-by: Hayato Hasegawa <hase1225hayato@gmail.com> Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> Co-authored-by: Junior Garcia <jrgarciadev@gmail.com> Co-authored-by: brianatdetections <brian@detections.ai> Co-authored-by: Brian Meek <brian@current.space> Co-authored-by: Dominik Hryshaiev <domhryshaiev@gmail.com> Co-authored-by: creative-atish <149860680+atishkr25@users.noreply.github.com> Co-authored-by: KyZy7 <29321162+KyZy7@users.noreply.github.com> Co-authored-by: Deepansh Bhargava <deepansh940@gmail.com> Co-authored-by: KumJungMin <37934668+KumJungMin@users.noreply.github.com> Co-authored-by: Bohdan Kulinchenko <35272606+ITBoomBKStudio@users.noreply.github.com> Co-authored-by: doki- <1335902682@qq.com> Co-authored-by: Chris Nowak <krzysztofmareknowak@gmail.com>
⚽️ Current behavior (updates)
When using the
asprop with components created viaextendVariants, the component was rendered as the value passed toasinstead of rendering as the original base component.This caused components to lose the original rendering semantics and styles.
🚀 New behavior
Components created with
extendVariantsnow always render as the original base component.The
asprop no longer changes the rendered element, restoring the expected rendering behavior.