Fix filter multi select (#8682)

- Created a dropdown inside a dropdown for the
`ObjectFilterDropdownOperandDropdown` so the operand can be opened over
the selection with an offset
- Refactored dropdown component and introduced `DropdownUnmountEffect`
to close the dropdown when the component unmounts
- Removed old logic

Before:
<img width="216" alt="Capture d’écran 2024-11-22 à 14 03 58"
src="https://github.com/user-attachments/assets/3c1bba03-af03-4993-a070-f009b8dc876f">

After:
<img width="222" alt="Capture d’écran 2024-11-22 à 14 03 40"
src="https://github.com/user-attachments/assets/a8a784b4-8672-4b02-bb21-e4a749682f2e">
This commit is contained in:
Raphaël Bosi
2024-11-22 15:08:29 +01:00
committed by GitHub
parent ac9cf737fb
commit f44e2935df
19 changed files with 148 additions and 248 deletions

View File

@ -21,6 +21,7 @@ import { isDefined } from '~/utils/isDefined';
import { useDropdown } from '../hooks/useDropdown';
import { useInternalHotkeyScopeManagement } from '../hooks/useInternalHotkeyScopeManagement';
import { DropdownUnmountEffect } from '@/ui/layout/dropdown/components/DropdownUnmountEffect';
import { useListenClickOutsideV2 } from '@/ui/utilities/pointer-event/hooks/useListenClickOutsideV2';
import { DropdownMenu } from './DropdownMenu';
import { DropdownOnToggleEffect } from './DropdownOnToggleEffect';
@ -149,25 +150,38 @@ export const Dropdown = ({
);
return (
<DropdownScope dropdownScopeId={getScopeIdFromComponentId(dropdownId)}>
<div ref={containerRef} className={className}>
{clickableComponent && (
<div
ref={refs.setReference}
onClick={handleClickableComponentClick}
className={className}
>
{clickableComponent}
</div>
)}
{hotkey && (
<HotkeyEffect
hotkey={hotkey}
onHotkeyTriggered={handleHotkeyTriggered}
/>
)}
{isDropdownOpen && usePortal && (
<FloatingPortal>
<>
<DropdownScope dropdownScopeId={getScopeIdFromComponentId(dropdownId)}>
<div ref={containerRef} className={className}>
{clickableComponent && (
<div
ref={refs.setReference}
onClick={handleClickableComponentClick}
className={className}
>
{clickableComponent}
</div>
)}
{hotkey && (
<HotkeyEffect
hotkey={hotkey}
onHotkeyTriggered={handleHotkeyTriggered}
/>
)}
{isDropdownOpen && usePortal && (
<FloatingPortal>
<DropdownMenu
disableBlur={disableBlur}
width={dropdownMenuWidth ?? dropdownWidth}
data-select-disable
ref={refs.setFloating}
style={floatingStyles}
>
{dropdownComponents}
</DropdownMenu>
</FloatingPortal>
)}
{isDropdownOpen && !usePortal && (
<DropdownMenu
disableBlur={disableBlur}
width={dropdownMenuWidth ?? dropdownWidth}
@ -177,24 +191,14 @@ export const Dropdown = ({
>
{dropdownComponents}
</DropdownMenu>
</FloatingPortal>
)}
{isDropdownOpen && !usePortal && (
<DropdownMenu
disableBlur={disableBlur}
width={dropdownMenuWidth ?? dropdownWidth}
data-select-disable
ref={refs.setFloating}
style={floatingStyles}
>
{dropdownComponents}
</DropdownMenu>
)}
<DropdownOnToggleEffect
onDropdownClose={onClose}
onDropdownOpen={onOpen}
/>
</div>
</DropdownScope>
)}
<DropdownOnToggleEffect
onDropdownClose={onClose}
onDropdownOpen={onOpen}
/>
</div>
</DropdownScope>
<DropdownUnmountEffect dropdownId={dropdownId} />
</>
);
};

View File

@ -49,6 +49,7 @@ type DropdownMenuHeaderProps = ComponentProps<'li'> & {
EndIcon?: IconComponent;
onClick?: (event: MouseEvent<HTMLButtonElement>) => void;
testId?: string;
className?: string;
};
export const DropdownMenuHeader = ({
@ -57,12 +58,17 @@ export const DropdownMenuHeader = ({
EndIcon,
onClick,
testId,
className,
}: DropdownMenuHeaderProps) => {
const theme = useTheme();
return (
<>
{EndIcon && (
<StyledHeader data-testid={testId} onClick={onClick}>
<StyledHeader
data-testid={testId}
onClick={onClick}
className={className}
>
<StyledChildrenWrapper>{children}</StyledChildrenWrapper>
<StyledEndIcon>
<EndIcon size={theme.icon.size.md} />
@ -70,7 +76,7 @@ export const DropdownMenuHeader = ({
</StyledHeader>
)}
{StartIcon && (
<StyledHeader data-testid={testId}>
<StyledHeader data-testid={testId} className={className}>
<LightIconButton
testId="dropdown-menu-header-end-icon"
Icon={StartIcon}

View File

@ -37,12 +37,17 @@ const StyledDropdownMenuItemsInternalContainer = styled.div`
export const DropdownMenuItemsContainer = ({
children,
hasMaxHeight,
className,
}: {
children: React.ReactNode;
hasMaxHeight?: boolean;
className?: string;
}) => {
return (
<StyledDropdownMenuItemsExternalContainer hasMaxHeight={hasMaxHeight}>
<StyledDropdownMenuItemsExternalContainer
hasMaxHeight={hasMaxHeight}
className={className}
>
{hasMaxHeight ? (
<StyledScrollWrapper contextProviderName="dropdownMenuItemsContainer">
<StyledDropdownMenuItemsInternalContainer>

View File

@ -0,0 +1,18 @@
import { useDropdownV2 } from '@/ui/layout/dropdown/hooks/useDropdownV2';
import { useEffect } from 'react';
export const DropdownUnmountEffect = ({
dropdownId,
}: {
dropdownId: string;
}) => {
const { closeDropdown } = useDropdownV2();
useEffect(() => {
return () => {
closeDropdown(dropdownId);
};
}, [closeDropdown, dropdownId]);
return null;
};