Closed matteo-pkxp closed 1 week ago
I found a not-so-elegant solution to ignore the TS error:
<DropdownMenu aria-label="Profile Actions" variant="flat">
{[
// @ts-ignore
menuItems.map((entry) => (
<DropdownItem key={entry.link}>
{entry.name}
</DropdownItem>
)),
<DropdownItem key="custom">Test123</DropdownItem>,
]}
</DropdownMenu>
This suppresses the TS error, renders the Dropdown as expected and throws no runtime errors, but I'm sure there's a better solution.
Option number 2, which is probably the best one:
<DropdownMenu aria-label="Profile Actions" variant="flat">
<DropdownSection>
{ menuItems.map((entry) => (
<DropdownItem key={entry.link} showDivider={entry.divider}>
{entry.name}
</DropdownItem>
))}
</DropdownSection>
<DropdownItem key="custom">Test123</DropdownItem>
</DropdownMenu>
The only downside here is the aria-label warning, because It's a titleless section.
Not sure if I should close the issue though. I don't think the errors I encountered are expected.
Hello~
I did some research to figure this out. so the underlying of menu is using react-aria-components. if you wish to render dynamic items, I think the proper way should go with this
<DropdownMenu aria-label="Profile Actions" variant="flat" items={menuItems}>
{(item) => <DropdownItem key={item.key} showDivider={item.divider} />}
</DropdownMenu>
you can find the reason why suggest to use items
props instead of Array.map here
Hi! Thanks for the suggestion, this is surely something that's good to know. Unfortunately, it doesn't fix the issue.
Type '(item: MenuEntry) => JSX.Element' is not assignable to type 'CollectionChildren<object>'.
Type '(item: MenuEntry) => JSX.Element' is not assignable to type '(item: object) => CollectionElement<object>'.
Types of parameters 'item' and 'item' are incompatible.
Property 'name' is missing in type '{}' but required in type 'MenuEntry'.ts(2322)
Looks like it's a Typescript incompatibility of some sort. The dropdown gets rendered as intended, it's just the compiler that goes crazy.
Also, if I do something like this below, only the "custom" element gets rendered:
<DropdownMenu aria-label="Profile Actions" variant="flat" items={menuItems}>
{(item) => <DropdownItem key={item.key} showDivider={item.divider} />}
<DropdownItem key="custom">Test123</DropdownItem>
</DropdownMenu>
The only solution is to use the DropdownSection component, that supports the items
prop.
<DropdownMenu aria-label="Profile Actions" variant="flat">
<DropdownSection items={menuItems} aria-label="I'd rather not set this, it has no meaning to me in this case">
{(item) => <DropdownItem key={item.key} showDivider={item.divider} />}
</DropdownSection>
<DropdownItem key="custom">Test123</DropdownItem>
</DropdownMenu>
I'm having same issue
Hey ! I see you closed this in 2.2.0 @jrgarciadev ?
I'm still having this issue with the following in 2.2.1:
<Dropdown placement="bottom-end">
<DropdownMenu aria-label="Profile Actions" variant="flat">
{session.user?.isAdmin && (
<DropdownSection title="Admin" showDivider>
<DropdownItem key="prisma">Whatever</DropdownItem>
</DropdownSection>
)}
</DropdownMenu>
</Dropdown>
Same symptoms, ts-error, then runtime error if wrapping it inside a fragment 😕
My code that is experiencing the same error in 2.2.8:
{
notificationsData.map((notification) => {
return (
<DropdownItem key={notification.id}>
<Notification
body={notification.body}
date={notification.createdAt}
read={notification.read}
/>
</DropdownItem>
)
})
}
@xavier-villelegier Do you know of a work around?
Hey guys I'm trying to figure out ways to fix this, the react-aria collection API only accepts specific components as children (Item, Section) to build the collection, that's why it fails when trying to pass custom components.
@aaronhawkey did you try using the Dropdown dynamic render?
import React from "react";
import {Dropdown, DropdownTrigger, DropdownMenu, DropdownItem, Button} from "@nextui-org/react";
export default function App() {
const notificationsData = [
{
key: "1",
read: false,
body: "First message",
createdAt: null
},
{
key: "2",
read: false,
body: "Second Message",
createdAt: null
},
{
key: "3",
read: false,
body: "Third message",
createdAt: null
},
];
return (
<Dropdown>
<DropdownTrigger>
<Button
variant="bordered"
>
Open Menu
</Button>
</DropdownTrigger>
<DropdownMenu aria-label="Notifications" items={notificationsData}>
{(notification) => (
<DropdownItem key={item.key} textValue={notification.body}>
<Notification
body={notification.body}
date={notification.createdAt}
read={notification.read}
/>
</DropdownItem>
)}
</DropdownMenu>
</Dropdown>
);
}
Hey, I'm struggling with a similar issue, although in my case it's with the DropdownSection
:
<DropdownSection showDivider key={"notifications"} items={notifications}>
{(item: any) => (
<DropdownItem
key={item.id}
onPress={notificationPressHandler}
className={styles.notification__wrapper}
>
<span className={styles.notification__topic}>{item.topic}</span>
<p className={styles.notification__content}>{item.content}</p>
</DropdownItem>
)}
</DropdownSection>
This is only a TypeScript error, I'll be using ts-ignore
for now to avoid it. Components render fine.
Hey ! I see you closed this in 2.2.0 @jrgarciadev ?
I'm still having this issue with the following in 2.2.1:
<Dropdown placement="bottom-end"> <DropdownMenu aria-label="Profile Actions" variant="flat"> {session.user?.isAdmin && ( <DropdownSection title="Admin" showDivider> <DropdownItem key="prisma">Whatever</DropdownItem> </DropdownSection> )} </DropdownMenu> </Dropdown>
Same symptoms, ts-error, then runtime error if wrapping it inside a fragment 😕
i have same isue for this
you can try this bad solution
let dropdownItems = [
{
key: 'profile',
label: 'Profile',
},
{
key: 'signout',
label: 'Signout',
},
];
if (auth?.user.role !== 'USER') {
dropdownItems.push({
key: 'dashboard',
label: 'Dashboard',
});
}
//return
<DropdownMenu
aria-label='dynamic'
items={dropdownItems}
>
{(item) => (
<DropdownItem
key={item.key}
color={item.key === 'signout' ? 'danger' : 'default'}
className={item.key === 'signout' ? 'text-danger' : ''}
>
{item.label}
</DropdownItem>
)}
</DropdownMenu>
const list = [ { key: '1', value: 'item_1'}, { key: '2', value: 'item_2'}, ]
Hey guys I'm trying to figure out ways to fix this, the react-aria collection API only accepts specific components as children (Item, Section) to build the collection, that's why it fails when trying to pass custom components.
@aaronhawkey did you try using the Dropdown dynamic render?
import React from "react"; import {Dropdown, DropdownTrigger, DropdownMenu, DropdownItem, Button} from "@nextui-org/react"; export default function App() { const notificationsData = [ { key: "1", read: false, body: "First message", createdAt: null }, { key: "2", read: false, body: "Second Message", createdAt: null }, { key: "3", read: false, body: "Third message", createdAt: null }, ]; return ( <Dropdown> <DropdownTrigger> <Button variant="bordered" > Open Menu </Button> </DropdownTrigger> <DropdownMenu aria-label="Notifications" items={notificationsData}> {(notification) => ( <DropdownItem key={item.key} textValue={notification.body}> <Notification body={notification.body} date={notification.createdAt} read={notification.read} /> </DropdownItem> )} </DropdownMenu> </Dropdown> ); }
Sorry for the late reply. I did and it worked for me.
None of the above solutions work for me for conditional rendering. I managed to implement a slightly tricky solution by using Type Guard, like so:
function testT<T>(input: T | false | undefined | null): input is T {
return Boolean(input)
}
function filter<T>(input: (T | false | undefined | null)[]): T[] {
return input.filter(testT)
}
...
<DropdownSection showDivider>
{/* here comes the above 'filter 'function */}
{filter([
hasUnpublished && (
<DropdownItem key="publish" className="text-success">
Publish
</DropdownItem>
),
hasPublished && (
<DropdownItem key="unpublish" className="text-warning">
Unpublish
</DropdownItem>
),
])}
</DropdownSection>
If you use a ternary if ? : you can return a empty DropdownItem with a className of "hidden". It will work. Or just hide the the DropdownItem with a "hidden" class. If it's a client component then you'll be sending the javascript of all anyways.
This should work
<DropdownMenu aria-label="Profile Actions" variant="flat">
{menuItems ? (
menuItems.map((entry) => (
<DropdownItem key={entry.link} showDivider={entry.divider}>
{entry.name}
</DropdownItem>
))
) : (
<DropdownItem>handle this, if there is no data</DropdownItem>
)}
<DropdownItem key="custom">Test123</DropdownItem>
</DropdownMenu>
I think this is a big bug,DropdownMenu no longer seems to accept the prop of children. in vscode,eslint error:不能将类型“{ children: (item: { link: string; name: string; }) => Element; "aria-label": string; items: { link: string; name: string; }[]; }”分配给类型“IntrinsicAttributes & Props
update nextui
August 2024 and the issue is still happening is there a fix in the way?
@MFRamon can you share your code reproducing the issue? I saw some usages aren't really bugs but misuse of the collection-based components.
Sure @wingkwong .
Actually a few hours back I figured out the issue. Apparently in version 2.4.6 is not happening, what I did was delete the node_modules folder and reinstall dependencies. Maybe I had the older version from nextui installed. Now It's rendering and working now. But posting the code here just in case you have any suggestions or comments.
<Dropdown placement="right-end">
<DropdownTrigger>
<button>Button</button>
</DropdownTrigger>
<DropdownMenu variant="faded" aria-label="Dropdown menu title" className="w-[17vw] !p-0">
<DropdownSection title={undefined} className="" id="section-titulos">
<DropdownItem endContent={<button>Mark all as read</button>}>NOTIFICATIONS</DropdownItem>
</DropdownSection>
<DropdownSection title={undefined}>
{items.map((item) => (
<DropdownItem className="" key={item.key}>
{item.label}
</DropdownItem>
))}
</DropdownSection>
<DropdownSection title={undefined} className="" id="section-titulos">
<DropdownItem>NOTIFICATIONS</DropdownItem>
</DropdownSection>
</DropdownMenu>
</Dropdown>
Version in package.json is :
"@nextui-org/react": "^2.4.6",
.
.
.
Hopefully it's helpful for someone else
I'm closing this issue since I couldn't reproduce any typescript error. Please note that this is a collection-based component and make sure there is at least one child there. The following example would fail because if session.user?.isAdmin
is false, then there won't be any child which breaks the parsing.
<Dropdown placement="bottom-end">
<DropdownMenu aria-label="Profile Actions" variant="flat">
{session.user?.isAdmin && (
<DropdownSection title="Admin" showDivider>
<DropdownItem key="prisma">Whatever</DropdownItem>
</DropdownSection>
)}
</DropdownMenu>
</Dropdown>
NextUI Version
2.1.13
Describe the bug
Hello, I have a type issue when using the Dropdown component, this is the code triggering the ts error:
The error is:
Type 'Element[]' is not assignable to type 'CollectionElement<object>'
. The code runs fine and the result is as expected, that is a list of DropdownItems followed by the non-iterated "Test123" item, but the error (that I couldn't suppress) prevents me from building the app for production.If I wrap it with a fragment
<></>
, which makes the TS error disappear, this time the error is at runtime and becomesTypeError: Cannot convert a Symbol value to a string
.Any idea on how to make it work? I have custom element at the bottom of this dropdown, that doesn't match the structure of the iterated elements.
Your Example Website or App
No response
Steps to Reproduce the Bug or Issue
I'm using Typescript 5.1.6 and NextJS 13.4.13
Expected behavior
There should be either no runtime or linter errors.
Screenshots or Videos
No response
Operating System Version
Windows with Linux Subsystem 2.0 (Debian LTS)
Browser
Chrome