-
-
Notifications
You must be signed in to change notification settings - Fork 1.6k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
fix: forwardRef render functions not using ref #4099
base: beta/release-next
Are you sure you want to change the base?
Conversation
The latest updates on your projects. Learn more about Vercel for Git ↗︎
|
🦋 Changeset detectedLatest commit: 1bd9fd9 The changes in this PR will be included in the next version bump. This PR includes changesets to release 29 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 |
Important Review skippedAuto reviews are disabled on base/target branches other than the default branch. 🗂️ Base branches to auto review (5)
Please check the settings in the CodeRabbit UI or the You can disable this status message by setting the WalkthroughThis pull request introduces a patch to several components from the Changes
Possibly related PRs
Suggested labels
Suggested reviewers
Thank you for using CodeRabbit. We offer it for free to the OSS community and would appreciate your support in helping us grow. If you find it useful, would you consider giving us a shout-out on your favorite social media? 🪧 TipsChatThere are 3 ways to chat with CodeRabbit:
Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments. CodeRabbit Commands (Invoked using PR comments)
Other keywords and placeholders
Documentation and Community
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 1
🧹 Outside diff range and nitpick comments (4)
.changeset/sharp-years-raise.md (1)
11-11
: Enhance the changeset description with more detailsWhile the description identifies the core issue, it would be helpful to include:
- The specific problem with ref usage that was fixed
- The impact of this change on component behavior
- Any migration steps if developers need to update their code
Example of a more detailed description:
-fix forwardRef render functions not using ref +fix forwardRef render functions not using ref + +Previously, some components weren't properly utilizing the ref parameter in their +forwardRef render functions. This has been fixed by introducing wrapForwardRefTypes +utility, ensuring proper ref forwarding in Dropdown, Listbox, Menu, Modal, and +Popover components. + +This change: +- Improves type safety for forwarded refs +- Maintains backward compatibility +- Requires no changes from consumerspackages/components/dropdown/src/dropdown-trigger.tsx (1)
1-1
: Consider documenting the ref handling behaviorThe switch from
forwardRef
towrapForwardRefTypes
represents a significant change in ref handling. Consider adding documentation to explain:
- Why
wrapForwardRefTypes
is preferred overforwardRef
- How refs are properly forwarded to the underlying
PopoverTrigger
Also applies to: 14-20
packages/core/system/src/index.ts (1)
28-28
: Documentation needed for the new export.Since
wrapForwardRefTypes
is a new utility function being exposed, please ensure it's properly documented with its purpose, usage examples, and any breaking changes from the previousforwardRef
implementation.Consider adding:
- JSDoc comments explaining the utility's purpose
- Code examples showing migration from
forwardRef
- Type documentation for TypeScript users
packages/core/system-rsc/src/utils.ts (1)
21-34
: Add documentation explaining the difference between forwardRef and wrapForwardRefTypesTo prevent confusion and misuse, please add JSDoc comments explaining:
- The purpose of this utility
- How it differs from
forwardRef
- When to use each function
+/** + * Wraps a forward ref render function with proper TypeScript types. + * Unlike `forwardRef`, this utility only provides type information without runtime wrapping. + * + * @warning Only use this if the component is already wrapped with React.forwardRef + */ export function wrapForwardRefTypes<
📜 Review details
Configuration used: .coderabbit.yaml
Review profile: CHILL
📒 Files selected for processing (10)
.changeset/sharp-years-raise.md
(1 hunks)packages/components/dropdown/src/dropdown-trigger.tsx
(2 hunks)packages/components/listbox/src/listbox-item.tsx
(2 hunks)packages/components/menu/src/menu-item.tsx
(2 hunks)packages/components/modal/src/modal-content.tsx
(2 hunks)packages/components/popover/src/popover-content.tsx
(2 hunks)packages/components/popover/src/popover-trigger.tsx
(2 hunks)packages/core/system-rsc/src/index.ts
(1 hunks)packages/core/system-rsc/src/utils.ts
(1 hunks)packages/core/system/src/index.ts
(1 hunks)
🔇 Additional comments (15)
.changeset/sharp-years-raise.md (1)
1-9
: LGTM: Consistent patch versioning across packages
The patch version bumps are appropriate for this type of fix, and the scope of changes correctly includes all affected packages.
packages/core/system-rsc/src/index.ts (2)
24-24
: LGTM! Export addition is well-placed
The new export of wrapForwardRefTypes
is appropriately placed with other utility exports.
24-24
: Verify the implementation and usage of wrapForwardRefTypes
Let's verify the implementation of this new utility and its usage across components.
✅ Verification successful
Implementation and usage of wrapForwardRefTypes is properly verified
The utility wrapForwardRefTypes
is implemented in packages/core/system-rsc/src/utils.ts
and is being used correctly across multiple components:
- Modal content component
- Listbox item component
- Menu item component
- Popover content and trigger components
- Dropdown trigger component
The implementation is a type-safe wrapper for React's forwardRef pattern, ensuring proper type inference for component props and refs. Its usage is consistent across the codebase, primarily in components that need ref forwarding capabilities.
🏁 Scripts executed
The following scripts were executed for the analysis:
Script:
#!/bin/bash
# Description: Verify the implementation and usage of wrapForwardRefTypes
# Check the implementation
echo "Checking wrapForwardRefTypes implementation:"
rg -A 10 "export.*wrapForwardRefTypes" "./packages/core/system-rsc/src/utils"
# Check its usage across components mentioned in the summary
echo "\nChecking usage in components:"
rg "wrapForwardRefTypes" \
--type ts \
--type tsx \
-g "packages/*/{dropdown,listbox,menu,modal,popover}/**"
Length of output: 457
Script:
#!/bin/bash
# Let's try a different approach to find the implementation and usage
# First, let's find the implementation file
echo "Finding implementation file:"
fd "wrapForwardRefTypes" --type f
# Then check for the implementation
echo -e "\nChecking implementation:"
rg -A 10 "wrapForwardRefTypes"
# Check usage across all TypeScript files
echo -e "\nChecking usage across the codebase:"
rg "wrapForwardRefTypes" --type typescript
Length of output: 12842
packages/components/dropdown/src/dropdown-trigger.tsx (1)
14-14
: Verify ref handling in the component
The ref parameter is marked as unused (_
), which seems to contradict the PR's objective of fixing forwardRef render functions not using ref. Please ensure this is intentional and doesn't defeat the purpose of the fix.
Let's verify how refs are handled in the system:
✅ Verification successful
Unused ref parameter is correct in this implementation
The underscore parameter in DropdownTrigger
is intentional and correct because:
- The component delegates all ref handling to
PopoverTrigger
PopoverTrigger
properly manages refs through the popover context'striggerRef
andgetTriggerProps
- The component composition pattern ensures refs are properly forwarded despite the underscore parameter
🏁 Scripts executed
The following scripts were executed for the analysis:
Script:
#!/bin/bash
# Check the implementation of wrapForwardRefTypes
rg -A 10 "export.*wrapForwardRefTypes" packages/components/system/
# Check if other components follow the same pattern
ast-grep --pattern 'wrapForwardRefTypes<$_>($_, _)'
Length of output: 190
Script:
#!/bin/bash
# Let's try to find the wrapForwardRefTypes implementation first
fd -e ts -e tsx wrapForwardRefTypes --exec rg -l "export.*wrapForwardRefTypes" {}
# Then look for its content
fd -e ts -e tsx wrapForwardRefTypes --exec rg -A 10 "export.*wrapForwardRefTypes" {}
# Check for similar patterns in dropdown components
fd -e tsx dropdown-trigger --exec rg -A 10 "wrapForwardRefTypes" {}
# Look for other components using similar pattern
rg "wrapForwardRefTypes.*_" -A 5
Length of output: 1588
Script:
#!/bin/bash
# Let's check the PopoverTrigger implementation since DropdownTrigger delegates to it
fd -e tsx popover-trigger --exec rg -A 10 "wrapForwardRefTypes|forwardRef" {}
# Let's also check the system package for wrapForwardRefTypes
fd -e ts -e tsx -g "**/system/**" --exec rg -A 10 "wrapForwardRefTypes" {}
# Check if there are any ref usages in the PopoverTrigger
fd -e tsx popover-trigger --exec rg -A 10 "\.ref" {}
Length of output: 1466
Script:
#!/bin/bash
# Let's check the PopoverContext to understand how triggerRef is used
fd -e tsx popover-context --exec rg -A 10 "triggerRef" {}
# Check getTriggerProps implementation
fd -e tsx -g "**/popover/**" --exec rg -A 10 "getTriggerProps.*=.*{" {}
# Let's also check the usePopover hook if it exists
fd -e ts -e tsx -g "**/popover/**" --exec rg -A 10 "usePopover.*=|export.*usePopover" {}
Length of output: 228
packages/core/system/src/index.ts (1)
28-28
: Verify the impact of wrapForwardRefTypes.
The addition aligns with fixing the forwardRef render functions. Let's verify the implementation and usage across components.
✅ Verification successful
Let me gather more information about the usage and implementation to verify the impact.
The addition of wrapForwardRefTypes
is safe and properly implemented
The implementation is a type-safe wrapper for React's forwardRef components, providing better type inference for polymorphic components. The export is already being used in the system-rsc package and doesn't break existing forwardRef implementations. The changes align with the PR's goal of improving ref handling.
🏁 Scripts executed
The following scripts were executed for the analysis:
Script:
#!/bin/bash
# Description: Check the implementation and usage of wrapForwardRefTypes
# Expected: Find the implementation and verify components using it correctly
# Check implementation
echo "Checking wrapForwardRefTypes implementation:"
rg -A 10 "export.*wrapForwardRefTypes" packages/core/system-rsc/
# Check usage in components
echo "\nChecking component usage:"
rg "wrapForwardRefTypes" packages/core/ -l
Length of output: 1057
Script:
#!/bin/bash
# Check the implementation details and type definitions
echo "Checking wrapForwardRefTypes implementation details:"
rg -A 20 "export function wrapForwardRefTypes" packages/core/system-rsc/src/utils.ts
# Check if there are any existing forwardRef usages that need to be migrated
echo "\nChecking existing forwardRef usages:"
rg "forwardRef\(" packages/core/
# Check if there are any existing type exports for forwardRef
echo "\nChecking existing forwardRef type exports:"
rg "export.*forwardRef" packages/core/
Length of output: 1595
packages/components/popover/src/popover-trigger.tsx (2)
2-2
: Verify the system package export
Let's ensure the wrapForwardRefTypes
utility is properly exported from the system package.
#!/bin/bash
# Description: Verify the export of wrapForwardRefTypes from @nextui-org/system
# Check if wrapForwardRefTypes is exported from system package
rg -g 'packages/core/system*/src/*.ts' -A 3 'export.*wrapForwardRefTypes'
# Check if other components are using this utility consistently
rg -g 'packages/components/*/src/*.tsx' 'wrapForwardRefTypes'
18-18
: Verify ref behavior compatibility
The change from forwardRef
to wrapForwardRefTypes
looks good for improved type safety. However, we should ensure this doesn't break existing ref usage patterns.
Consider documenting this change in the component's API documentation if the ref behavior has been enhanced or modified in any way.
packages/components/listbox/src/listbox-item.tsx (2)
2-2
: LGTM: Clean import of the new utility function
The import of wrapForwardRefTypes
from the system package is well-placed and aligns with the PR's objective of improving ref handling.
12-12
: Verify ref forwarding behavior remains intact
The switch to wrapForwardRefTypes
looks good and removes the unused ref parameter. Since this is a core change in ref handling, we should verify that refs are still properly forwarded to the underlying li
element.
Let's verify the ref handling implementation:
✅ Verification successful
Let me try another verification approach since the previous commands had issues with the tsx file type.
Let me check the test file and the implementation of wrapForwardRefTypes to make a final determination.
Ref forwarding behavior is properly maintained
The switch to wrapForwardRefTypes
is safe because:
- The implementation in
utils.ts
shows thatwrapForwardRefTypes
correctly preserves the type information and ref handling capabilities - The test file includes ref forwarding tests for the Listbox component, which passes through the same ref handling mechanism
wrapForwardRefTypes
maintains the same type signature as the originalforwardRef
implementation, ensuring type safety and ref compatibility
🏁 Scripts executed
The following scripts were executed for the analysis:
Script:
#!/bin/bash
# Description: Check for ref usage patterns in tests and consuming components
# Check for ListboxItem ref usage in test files
echo "Checking for ListboxItem ref usage in tests..."
rg -l "ListboxItem.*useRef|useRef.*ListboxItem" --type ts --type tsx
# Check for direct ref assignments to ListboxItem
echo "Checking for direct ref assignments..."
rg -l "ref=.*ListboxItem|<ListboxItem.*ref=" --type ts --type tsx
# Look for wrapForwardRefTypes implementation
echo "Checking wrapForwardRefTypes implementation..."
rg -A 10 "export.*wrapForwardRefTypes" --type ts
Length of output: 1212
Script:
#!/bin/bash
# Search for ListboxItem ref usage with correct file type flags
echo "Checking ListboxItem ref usage..."
rg -A 5 "<ListboxItem.*ref" .
# Check wrapForwardRefTypes implementation and usage
echo "Checking wrapForwardRefTypes implementation..."
ast-grep --pattern 'export function wrapForwardRefTypes<$_>($_) { $$$ }'
# Look for ListboxItem tests
echo "Finding ListboxItem tests..."
fd "listbox.*test" --type f
Length of output: 2181
Script:
#!/bin/bash
# Check the test file content for ref testing
echo "Checking listbox test content..."
cat packages/components/listbox/__tests__/listbox.test.tsx
# Look for wrapForwardRefTypes implementation details
echo "Checking wrapForwardRefTypes implementation..."
cat packages/core/system-rsc/src/utils.ts
Length of output: 12087
packages/components/menu/src/menu-item.tsx (2)
2-2
: LGTM: Import of wrapForwardRefTypes utility
The import statement is correctly placed and aligns with the PR's objective of improving ref handling.
12-12
: Verify ref forwarding functionality
The switch to wrapForwardRefTypes
looks good, but we should verify that refs are properly forwarded to the underlying li
element.
✅ Verification successful
Let me gather more information about the wrapForwardRefTypes
implementation.
Let me check the complete implementation of wrapForwardRefTypes
and the menu item tests.
Based on the gathered information, I can now provide the final response:
Ref forwarding is properly implemented
The switch to wrapForwardRefTypes
is safe and correctly handles ref forwarding:
- The utility is a type-safe wrapper that preserves the forwarded ref functionality
- The implementation in
utils.ts
shows it properly handles the ref types - The test suite verifies ref forwarding for the Menu component
- Multiple other components in the codebase successfully use this pattern
🏁 Scripts executed
The following scripts were executed for the analysis:
Script:
#!/bin/bash
# Description: Verify that wrapForwardRefTypes is properly handling refs
# by checking its implementation and usage patterns
# Check the implementation of wrapForwardRefTypes
ast-grep --pattern 'export const wrapForwardRefTypes = $_'
# Check for other similar conversions to ensure consistency
ast-grep --pattern 'wrapForwardRefTypes<$_, $_>($_)'
# Look for test files that verify ref forwarding
fd -e test.tsx -e spec.tsx -e test.ts -e spec.ts | xargs rg "ref.*forwarded"
Length of output: 23894
Script:
#!/bin/bash
# Check the implementation of wrapForwardRefTypes
rg -A 10 "export.*wrapForwardRefTypes"
# Check if there are any tests specifically for wrapForwardRefTypes
rg -A 5 "wrapForwardRefTypes.*test"
# Look for menu item tests that verify ref forwarding
rg -A 5 "MenuItem.*ref" packages/components/menu/__tests__/
Length of output: 814
Script:
#!/bin/bash
# Get the complete implementation of wrapForwardRefTypes
rg -A 30 "export function wrapForwardRefTypes" packages/core/system-rsc/src/utils.ts
# Check menu item tests
cat packages/components/menu/__tests__/menu.test.tsx
# Check if there are any specific menu item ref tests
rg -l "MenuItem.*ref|ref.*MenuItem" packages/components/menu/__tests__/
Length of output: 11286
packages/core/system-rsc/src/utils.ts (1)
21-34
:
Potential ref handling issues with type casting approach
The wrapForwardRefTypes
function performs a type cast without actually wrapping the component with React's forwardRef
. This could lead to:
- Missing ref forwarding at runtime
- Bypassing React's development warnings
- Issues with hot reloading
Consider using baseForwardRef
like the existing forwardRef
function does:
export function wrapForwardRefTypes<
Component extends As,
Props extends object,
OmitKeys extends keyof any = never,
>(
component: React.ForwardRefRenderFunction<
any,
RightJoinProps<PropsOf<Component>, Props> & {
as?: As;
}
>,
) {
- return component as InternalForwardRefRenderFunction<Component, Props, OmitKeys>;
+ return baseForwardRef(component) as InternalForwardRefRenderFunction<Component, Props, OmitKeys>;
}
Let's verify how this utility is being used:
packages/components/popover/src/popover-content.tsx (2)
5-5
: LGTM: Import statement is correctly placed
The import of wrapForwardRefTypes
from the system package is appropriate for this utility function.
24-24
: Verify ref handling in wrapForwardRefTypes utility
The change from forwardRef
to wrapForwardRefTypes
aligns with fixing the unused ref issue. However, we should verify that refs are properly handled in the new utility.
✅ Verification successful
Let me gather more information about the implementation details of wrapForwardRefTypes
.
Let me gather one final piece of information to understand how the ref is being handled in the component chain.
Ref handling is properly implemented through the type system
The change to wrapForwardRefTypes
is safe and correctly handles refs. The utility is part of the core system and maintains type safety while providing proper ref forwarding through React's built-in mechanisms. The implementation:
- Preserves the component's type information through
InternalForwardRefRenderFunction
- Correctly handles the ref prop typing via React's
ForwardRefRenderFunction
- Is consistently used across other components in the codebase
🏁 Scripts executed
The following scripts were executed for the analysis:
Script:
#!/bin/bash
# Description: Verify the implementation of wrapForwardRefTypes to ensure proper ref handling
# Check the implementation of wrapForwardRefTypes
echo "Checking wrapForwardRefTypes implementation:"
rg -A 10 "export.*wrapForwardRefTypes"
# Check for any test files related to ref handling
echo "Checking for related tests:"
fd -e test.tsx -e spec.tsx | xargs rg "wrapForwardRefTypes|forwardRef"
Length of output: 2980
Script:
#!/bin/bash
# Get the full implementation of wrapForwardRefTypes
rg -B 5 -A 20 "export function wrapForwardRefTypes"
# Check if there are any usages of forwardRef inside wrapForwardRefTypes
ast-grep --pattern 'forwardRef($_)'
Length of output: 5333
Script:
#!/bin/bash
# Check for baseForwardRef implementation and type definitions
rg -B 5 -A 10 "baseForwardRef|InternalForwardRefRenderFunction" packages/core/system-rsc/src/
# Check the actual usage in PopoverContent
rg -A 10 "PopoverContent.*=.*wrapForwardRefTypes" packages/components/popover/
Length of output: 5718
packages/components/modal/src/modal-content.tsx (1)
5-5
: LGTM: Clean import addition
The import of wrapForwardRefTypes
is properly added and aligns with the component's needs.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
can you share some background context like how to test the original issue? is this for nextjs15 / react19? also please add some test cases if possible.
Closes #
📝 Description
⛳️ Current behavior (updates)
🚀 New behavior
💣 Is this a breaking change (Yes/No):
📝 Additional Information
Summary by CodeRabbit
New Features
wrapForwardRefTypes
for improved ref handling in various components.Bug Fixes
These updates improve component interoperability and maintain existing functionalities while enhancing type safety.