Fixed many dropdown bugs (#8256)

Many dropdown bugs have been fixed, more refactoring is needed.

Dropdown fixed : 
- Filter select
- Sort select
- Visible field select
- Hidden field select
- Multi item picker (phones, links, emails, etc.)
- Phone country select
This commit is contained in:
Lucas Bordeau
2024-11-01 09:23:01 +01:00
committed by GitHub
parent a287edd91b
commit c93d2bcd5e
15 changed files with 276 additions and 182 deletions

View File

@ -74,8 +74,8 @@ export const PhoneCountryPickerDropdownButton = ({
);
const handleChange = (countryCode: string) => {
onChange(countryCode);
closeDropdown();
onChange(countryCode);
};
const countries = useCountries();
@ -89,7 +89,6 @@ export const PhoneCountryPickerDropdownButton = ({
return (
<Dropdown
dropdownMenuWidth={'100%'}
dropdownId="country-picker-dropdown-id"
dropdownHotkeyScope={{ scope: CountryPickerHotkeyScope.CountryPicker }}
clickableComponent={

View File

@ -7,7 +7,7 @@ import {
size,
useFloating,
} from '@floating-ui/react';
import { MouseEvent, useEffect, useRef } from 'react';
import { MouseEvent, ReactNode, useRef } from 'react';
import { Keys } from 'react-hotkeys-hook';
import { Key } from 'ts-key-enum';
@ -27,8 +27,8 @@ import { DropdownOnToggleEffect } from './DropdownOnToggleEffect';
type DropdownProps = {
className?: string;
clickableComponent?: JSX.Element | JSX.Element[];
dropdownComponents: JSX.Element | JSX.Element[];
clickableComponent?: ReactNode;
dropdownComponents: ReactNode;
hotkey?: {
key: Keys;
scope: string;
@ -65,13 +65,8 @@ export const Dropdown = ({
}: DropdownProps) => {
const containerRef = useRef<HTMLDivElement>(null);
const {
isDropdownOpen,
toggleDropdown,
closeDropdown,
dropdownWidth,
setDropdownPlacement,
} = useDropdown(dropdownId);
const { isDropdownOpen, toggleDropdown, closeDropdown, dropdownWidth } =
useDropdown(dropdownId);
const offsetMiddlewares = [];
@ -83,18 +78,21 @@ export const Dropdown = ({
offsetMiddlewares.push(offset({ mainAxis: dropdownOffset.y }));
}
const { refs, floatingStyles, placement } = useFloating({
const { refs, floatingStyles } = useFloating({
placement: dropdownPlacement,
middleware: [
flip(),
size({
padding: 12 + 20, // 12px for padding bottom, 20px for dropdown bottom margin target
padding: 32,
apply: ({ availableHeight, elements }) => {
elements.floating.style.maxHeight =
availableHeight >= elements.floating.scrollHeight
? ''
: `${availableHeight}px`;
elements.floating.style.height = 'auto';
},
boundary: document.querySelector('#root') ?? undefined,
}),
...offsetMiddlewares,
],
@ -102,10 +100,6 @@ export const Dropdown = ({
strategy: dropdownStrategy,
});
useEffect(() => {
setDropdownPlacement(placement);
}, [placement, setDropdownPlacement]);
const handleHotkeyTriggered = () => {
toggleDropdown();
};

View File

@ -23,10 +23,10 @@ const StyledDropdownMenu = styled.div<{
display: flex;
height: 100%;
flex-direction: column;
z-index: 30;
overflow-y: auto;
overflow-x: hidden;
width: ${({ width = 160 }) =>
typeof width === 'number' ? `${width}px` : width};
`;

View File

@ -13,7 +13,6 @@ const StyledDropdownMenuItemsExternalContainer = styled.div<{
flex-direction: column;
gap: 2px;
max-height: ${({ hasMaxHeight }) => (hasMaxHeight ? '188px' : 'none')};
overflow-y: auto;
padding: var(--padding);
@ -34,6 +33,8 @@ const StyledDropdownMenuItemsInternalContainer = styled.div`
width: 100%;
`;
// TODO: refactor this, the dropdown should handle the max height behavior + scroll with the size middleware
// We should instead create a DropdownMenuItemsContainerScrollable or take for granted that it is the default behavior
export const DropdownMenuItemsContainer = ({
children,
hasMaxHeight,

View File

@ -0,0 +1,105 @@
import { useTheme } from '@emotion/react';
import { FunctionComponent, MouseEvent, ReactElement, ReactNode } from 'react';
import {
IconChevronRight,
IconComponent,
IconDotsVertical,
LightIconButton,
LightIconButtonProps,
} from 'twenty-ui';
import { SelectHotkeyScope } from '@/ui/input/types/SelectHotkeyScope';
import { Dropdown } from '@/ui/layout/dropdown/components/Dropdown';
import { MenuItemLeftContent } from '../internals/components/MenuItemLeftContent';
import {
StyledHoverableMenuItemBase,
StyledMenuItemLeftContent,
} from '../internals/components/StyledMenuItemBase';
import { MenuItemAccent } from '../types/MenuItemAccent';
export type MenuItemIconButton = {
Wrapper?: FunctionComponent<{ iconButton: ReactElement }>;
Icon: IconComponent;
accent?: LightIconButtonProps['accent'];
onClick?: (event: MouseEvent<any>) => void;
};
export type MenuItemWithOptionDropdownProps = {
accent?: MenuItemAccent;
className?: string;
dropdownContent: ReactNode;
dropdownId: string;
isIconDisplayedOnHoverOnly?: boolean;
isTooltipOpen?: boolean;
LeftIcon?: IconComponent | null;
RightIcon?: IconComponent | null;
onClick?: (event: MouseEvent<HTMLDivElement>) => void;
onMouseEnter?: (event: MouseEvent<HTMLDivElement>) => void;
onMouseLeave?: (event: MouseEvent<HTMLDivElement>) => void;
testId?: string;
text: ReactNode;
hasSubMenu?: boolean;
};
// TODO: refactor this
export const MenuItemWithOptionDropdown = ({
accent = 'default',
className,
isIconDisplayedOnHoverOnly = true,
dropdownContent,
dropdownId,
LeftIcon,
RightIcon,
onClick,
onMouseEnter,
onMouseLeave,
testId,
text,
hasSubMenu = false,
}: MenuItemWithOptionDropdownProps) => {
const theme = useTheme();
const handleMenuItemClick = (event: MouseEvent<HTMLDivElement>) => {
if (!onClick) return;
event.preventDefault();
event.stopPropagation();
onClick?.(event);
};
return (
<StyledHoverableMenuItemBase
data-testid={testId ?? undefined}
onClick={handleMenuItemClick}
className={className}
accent={accent}
isIconDisplayedOnHoverOnly={isIconDisplayedOnHoverOnly}
onMouseEnter={onMouseEnter}
onMouseLeave={onMouseLeave}
>
<StyledMenuItemLeftContent>
<MenuItemLeftContent LeftIcon={LeftIcon ?? undefined} text={text} />
</StyledMenuItemLeftContent>
<div className="hoverable-buttons">
<Dropdown
clickableComponent={
<LightIconButton
Icon={RightIcon ?? IconDotsVertical}
size="small"
/>
}
dropdownComponents={dropdownContent}
dropdownId={dropdownId}
dropdownHotkeyScope={{ scope: SelectHotkeyScope.Select }}
disableBlur
/>
</div>
{hasSubMenu && (
<IconChevronRight
size={theme.icon.size.sm}
color={theme.font.color.tertiary}
/>
)}
</StyledHoverableMenuItemBase>
);
};