dropdown update

This commit is contained in:
Nate Kelley 2025-03-14 13:31:52 -06:00
parent 9fea44cc60
commit dfede461bc
No known key found for this signature in database
GPG Key ID: FD90372AB8D98B4F
4 changed files with 56 additions and 34 deletions

View File

@ -21,22 +21,28 @@ export const SaveToCollectionsDropdown: React.FC<{
const [openCollectionModal, setOpenCollectionModal] = React.useState(false);
const [showDropdown, setShowDropdown] = React.useState(false);
const items: DropdownProps['items'] = useMemo(
() =>
(collectionsList || []).map<DropdownItem>((collection) => {
return {
value: collection.id,
label: collection.name,
selected: selectedCollections.some((id) => id === collection.id),
onClick: () => onClickItem(collection),
link: createBusterRoute({
route: BusterRoutes.APP_COLLECTIONS_ID,
collectionId: collection.id
})
};
}),
[collectionsList, selectedCollections]
);
const items: DropdownProps['items'] = useMemo(() => {
const collectionsItems = (collectionsList || []).map<DropdownItem>((collection) => {
return {
value: collection.id,
label: collection.name,
selected: selectedCollections.some((id) => id === collection.id),
onClick: () => onClickItem(collection),
link: createBusterRoute({
route: BusterRoutes.APP_COLLECTIONS_ID,
collectionId: collection.id
})
};
});
return [
...collectionsItems,
{
value: 'new',
label: 'New collection'
}
];
}, [collectionsList, selectedCollections]);
const onClickItem = useMemoizedFn((collection: BusterCollectionListItem) => {
const isSelected = selectedCollections.some((id) => id === collection.id);
@ -63,6 +69,7 @@ export const SaveToCollectionsDropdown: React.FC<{
const onOpenChange = useMemoizedFn((open: boolean) => {
setShowDropdown(open);
console.log('open', open);
});
const onClick = useMemoizedFn(() => {
@ -84,11 +91,12 @@ export const SaveToCollectionsDropdown: React.FC<{
side="bottom"
align="start"
menuHeader={'Save to a collection'}
open={showDropdown}
onOpenChange={onOpenChange}
footerContent={memoizedButton}
items={items}>
<AppTooltip title={showDropdown ? '' : 'Save to collection'}>{children} </AppTooltip>
<div>
<AppTooltip title={showDropdown ? '' : 'Save to collection'}>{children} </AppTooltip>
</div>
</Dropdown>
<NewCollectionModal

View File

@ -540,6 +540,13 @@ export const WithFooterContent: Story = {
}
};
export const WithFooterAndHeader: Story = {
args: {
...WithFooterContent.args,
menuHeader: 'Menu...'
}
};
// Example with numbered items
export const WithNumberedItemsNoFilter: Story = {
args: {
@ -565,6 +572,7 @@ export const WithNumberedItemsNoFilter: Story = {
label: 'Third Item',
onClick: fn(),
icon: <Storage />,
searchLabel: 'Third Item with secondary label',
secondaryLabel: 'With secondary label'
},
{

View File

@ -164,9 +164,9 @@ export const DropdownBase = <T,>({
className={cn('max-w-72 min-w-44', className)}
align={align}
side={side}
footerContent={footerContent}>
{menuHeader && (
<>
footerContent={footerContent}
headerContent={
menuHeader && (
<DropdownMenuHeaderSelector
menuHeader={menuHeader}
onChange={handleSearchChange}
@ -174,10 +174,8 @@ export const DropdownBase = <T,>({
onSelectItem={onSelectItem}
showIndex={showIndex}
/>
<DropdownMenuSeparator />
</>
)}
)
}>
<div className="max-h-[375px] overflow-y-auto">
{hasShownItem ? (
<>
@ -324,11 +322,12 @@ const DropdownItem = <T,>({
const content = (
<>
{icon && !loading && <span className="text-icon-color">{icon}</span>}
{loading && <CircleSpinnerLoader size={9} />}
<div className={cn('flex flex-col gap-y-1', truncate && 'overflow-hidden')}>
<span className={cn(truncate && 'truncate')}>{label}</span>
{secondaryLabel && <span className="text-gray-light text2xs">{secondaryLabel}</span>}
</div>
{loading && <CircleSpinnerLoader size={9} />}
{shortcut && <DropdownMenuShortcut>{shortcut}</DropdownMenuShortcut>}
{link && (
<DropdownMenuLink
@ -511,6 +510,7 @@ const DropdownMenuHeaderSearch = <T,>({
<Input
autoFocus
variant={'ghost'}
size={'small'}
placeholder={placeholder}
value={text}
onChange={onChangePreflight}

View File

@ -68,20 +68,24 @@ const DropdownMenuContent = React.forwardRef<
React.ElementRef<typeof DropdownMenuPrimitive.Content>,
React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.Content> & {
footerContent?: React.ReactNode;
headerContent?: React.ReactNode;
}
>(({ className, children, sideOffset = 4, footerContent, ...props }, ref) => {
const NodeWrapper = footerContent ? 'div' : 'span';
const nodeWrapperProps = footerContent ? { className: 'p-2' } : { className: '' };
>(({ className, children, sideOffset = 4, footerContent, headerContent, ...props }, ref) => {
return (
<DropdownMenuPrimitive.Portal>
<DropdownMenuPrimitive.Content
ref={ref}
sideOffset={sideOffset}
className={cn(baseContentClass, 'shadow', footerContent && 'p-0', className)}
className={cn(baseContentClass, 'shadow', 'p-0', className)}
{...props}>
<NodeWrapper {...nodeWrapperProps}>{children}</NodeWrapper>
{footerContent && <div className="border-t p-2">{footerContent}</div>}
{headerContent && (
<div className="flex flex-col">
<div className="p-1">{headerContent}</div>
<div className="bg-border h-[0.5px] w-full" />
</div>
)}
<div className="used-for-ref-purpose">{children}</div>
{footerContent && <div className="border-t p-1">{footerContent}</div>}
</DropdownMenuPrimitive.Content>
</DropdownMenuPrimitive.Portal>
);
@ -102,6 +106,7 @@ const DropdownMenuItem = React.forwardRef<
className={cn(
'relative flex cursor-pointer items-center gap-2 rounded-sm px-2 py-1.5 text-base outline-none select-none data-[disabled]:pointer-events-none data-[disabled]:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0',
'focus:bg-item-hover focus:text-foreground',
'dropdown-item mx-1 [&.dropdown-item:first-child]:mt-1! [&.dropdown-item:has(+.dropdown-separator)]:mb-1 [&.dropdown-item:has(~.dropdown-separator)]:mt-1 [&.dropdown-item:last-child]:mb-1!',
inset && 'pl-8',
truncate && 'overflow-hidden',
'group',
@ -123,7 +128,8 @@ const itemClass = cn(
'focus:bg-item-hover focus:text-foreground',
'relative flex cursor-pointer items-center rounded-sm py-1.5 text-sm outline-none select-none',
'data-[disabled]:pointer-events-none data-[disabled]:opacity-50',
'gap-1.5'
'gap-1.5',
'mx-1 dropdown-item [&.dropdown-item:has(+.dropdown-separator)]:mb-1 [&.dropdown-item:has(~.dropdown-separator)]:mt-1 [&.dropdown-item:first-child]:mt-1! [&.dropdown-item:last-child]:mb-1!'
);
const DropdownMenuCheckboxItemSingle = React.forwardRef<