feat: remove a link from a Links field (#5313)
Closes #5117 TO FIX in another PR: right now, the "Vertical Dots" LightIconButton inside the Dropdown menu sometimes needs to be clicked twice to open the nested dropdown, not sure why 🤔 Maybe an `event.preventDefault()` is needed somewhere? <img width="369" alt="image" src="https://github.com/twentyhq/twenty/assets/3098428/dd0c771a-c18d-4eb2-8ed6-b107f56711e9"> --------- Co-authored-by: Jérémy Magrin <jeremy.magrin@gmail.com> Co-authored-by: Charles Bochet <charles@twenty.com>
This commit is contained in:
@ -1,4 +1,4 @@
|
||||
import { MouseEvent } from 'react';
|
||||
import { FunctionComponent, MouseEvent, ReactElement } from 'react';
|
||||
import styled from '@emotion/styled';
|
||||
import { IconComponent } from 'twenty-ui';
|
||||
|
||||
@ -14,7 +14,9 @@ export type LightIconButtonGroupProps = Pick<
|
||||
'className' | 'size'
|
||||
> & {
|
||||
iconButtons: {
|
||||
Wrapper?: FunctionComponent<{ iconButton: ReactElement }>;
|
||||
Icon: IconComponent;
|
||||
accent?: LightIconButtonProps['accent'];
|
||||
onClick?: (event: MouseEvent<any>) => void;
|
||||
disabled?: boolean;
|
||||
}[];
|
||||
@ -26,16 +28,26 @@ export const LightIconButtonGroup = ({
|
||||
className,
|
||||
}: LightIconButtonGroupProps) => (
|
||||
<StyledLightIconButtonGroupContainer className={className}>
|
||||
{iconButtons.map(({ Icon, onClick }, index) => {
|
||||
return (
|
||||
{iconButtons.map(({ Wrapper, Icon, accent, onClick }, index) => {
|
||||
const iconButton = (
|
||||
<LightIconButton
|
||||
key={`light-icon-button-${index}`}
|
||||
Icon={Icon}
|
||||
accent={accent}
|
||||
disabled={!onClick}
|
||||
onClick={onClick}
|
||||
size={size}
|
||||
/>
|
||||
);
|
||||
|
||||
return Wrapper ? (
|
||||
<Wrapper
|
||||
key={`light-icon-button-wrapper-${index}`}
|
||||
iconButton={iconButton}
|
||||
/>
|
||||
) : (
|
||||
iconButton
|
||||
);
|
||||
})}
|
||||
</StyledLightIconButtonGroupContainer>
|
||||
);
|
||||
|
||||
@ -460,7 +460,7 @@ export const InternalDatePicker = ({
|
||||
/>
|
||||
</div>
|
||||
{clearable && (
|
||||
<StyledButtonContainer onClick={handleClear} isMenuOpen={false}>
|
||||
<StyledButtonContainer onClick={handleClear}>
|
||||
<StyledButton LeftIcon={IconCalendarX} text="Clear" />
|
||||
</StyledButtonContainer>
|
||||
)}
|
||||
|
||||
@ -36,6 +36,7 @@ type DropdownProps = {
|
||||
dropdownPlacement?: Placement;
|
||||
dropdownMenuWidth?: `${string}px` | `${number}%` | 'auto' | number;
|
||||
dropdownOffset?: { x?: number; y?: number };
|
||||
dropdownStrategy?: 'fixed' | 'absolute';
|
||||
disableBlur?: boolean;
|
||||
onClickOutside?: () => void;
|
||||
onClose?: () => void;
|
||||
@ -51,6 +52,7 @@ export const Dropdown = ({
|
||||
dropdownId,
|
||||
dropdownHotkeyScope,
|
||||
dropdownPlacement = 'bottom-end',
|
||||
dropdownStrategy = 'absolute',
|
||||
dropdownOffset = { x: 0, y: 0 },
|
||||
disableBlur = false,
|
||||
onClickOutside,
|
||||
@ -75,6 +77,7 @@ export const Dropdown = ({
|
||||
placement: dropdownPlacement,
|
||||
middleware: [flip(), ...offsetMiddlewares],
|
||||
whileElementsMounted: autoUpdate,
|
||||
strategy: dropdownStrategy,
|
||||
});
|
||||
|
||||
const handleHotkeyTriggered = () => {
|
||||
|
||||
@ -25,8 +25,8 @@ const StyledDropdownMenu = styled.div<{
|
||||
|
||||
flex-direction: column;
|
||||
z-index: 1;
|
||||
width: ${({ width }) =>
|
||||
width ? `${typeof width === 'number' ? `${width}px` : width}` : '160px'};
|
||||
width: ${({ width = 160 }) =>
|
||||
typeof width === 'number' ? `${width}px` : width};
|
||||
`;
|
||||
|
||||
export const DropdownMenu = StyledDropdownMenu;
|
||||
|
||||
@ -52,7 +52,7 @@ export const useDropdown = (dropdownId?: string) => {
|
||||
|
||||
return {
|
||||
scopeId,
|
||||
isDropdownOpen: isDropdownOpen,
|
||||
isDropdownOpen,
|
||||
closeDropdown,
|
||||
toggleDropdown,
|
||||
openDropdown,
|
||||
|
||||
@ -1,6 +1,7 @@
|
||||
import { MouseEvent, ReactNode } from 'react';
|
||||
import { FunctionComponent, MouseEvent, ReactElement, ReactNode } from 'react';
|
||||
import { IconComponent } from 'twenty-ui';
|
||||
|
||||
import { LightIconButtonProps } from '@/ui/input/button/components/LightIconButton';
|
||||
import { LightIconButtonGroup } from '@/ui/input/button/components/LightIconButtonGroup';
|
||||
|
||||
import { MenuItemLeftContent } from '../internals/components/MenuItemLeftContent';
|
||||
@ -11,7 +12,9 @@ import {
|
||||
import { MenuItemAccent } from '../types/MenuItemAccent';
|
||||
|
||||
export type MenuItemIconButton = {
|
||||
Wrapper?: FunctionComponent<{ iconButton: ReactElement }>;
|
||||
Icon: IconComponent;
|
||||
accent?: LightIconButtonProps['accent'];
|
||||
onClick?: (event: MouseEvent<any>) => void;
|
||||
};
|
||||
|
||||
@ -24,7 +27,7 @@ export type MenuItemProps = {
|
||||
isTooltipOpen?: boolean;
|
||||
className?: string;
|
||||
testId?: string;
|
||||
onClick?: (event: MouseEvent<HTMLLIElement>) => void;
|
||||
onClick?: (event: MouseEvent<HTMLDivElement>) => void;
|
||||
};
|
||||
|
||||
export const MenuItem = ({
|
||||
@ -32,7 +35,6 @@ export const MenuItem = ({
|
||||
accent = 'default',
|
||||
text,
|
||||
iconButtons,
|
||||
isTooltipOpen,
|
||||
isIconDisplayedOnHoverOnly = true,
|
||||
className,
|
||||
testId,
|
||||
@ -40,7 +42,7 @@ export const MenuItem = ({
|
||||
}: MenuItemProps) => {
|
||||
const showIconButtons = Array.isArray(iconButtons) && iconButtons.length > 0;
|
||||
|
||||
const handleMenuItemClick = (event: MouseEvent<HTMLLIElement>) => {
|
||||
const handleMenuItemClick = (event: MouseEvent<HTMLDivElement>) => {
|
||||
if (!onClick) return;
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
@ -54,7 +56,6 @@ export const MenuItem = ({
|
||||
onClick={handleMenuItemClick}
|
||||
className={className}
|
||||
accent={accent}
|
||||
isMenuOpen={!!isTooltipOpen}
|
||||
isIconDisplayedOnHoverOnly={isIconDisplayedOnHoverOnly}
|
||||
>
|
||||
<StyledMenuItemLeftContent>
|
||||
|
||||
@ -23,7 +23,6 @@ export const MenuItemDraggable = ({
|
||||
LeftIcon,
|
||||
accent = 'default',
|
||||
iconButtons,
|
||||
isTooltipOpen,
|
||||
onClick,
|
||||
text,
|
||||
isDragDisabled = false,
|
||||
@ -37,7 +36,6 @@ export const MenuItemDraggable = ({
|
||||
onClick={onClick}
|
||||
accent={accent}
|
||||
className={className}
|
||||
isMenuOpen={!!isTooltipOpen}
|
||||
isIconDisplayedOnHoverOnly={isIconDisplayedOnHoverOnly}
|
||||
>
|
||||
<MenuItemLeftContent
|
||||
|
||||
@ -10,7 +10,7 @@ export type MenuItemBaseProps = {
|
||||
isKeySelected?: boolean;
|
||||
};
|
||||
|
||||
export const StyledMenuItemBase = styled.li<MenuItemBaseProps>`
|
||||
export const StyledMenuItemBase = styled.div<MenuItemBaseProps>`
|
||||
--horizontal-padding: ${({ theme }) => theme.spacing(1)};
|
||||
--vertical-padding: ${({ theme }) => theme.spacing(2)};
|
||||
|
||||
@ -101,23 +101,26 @@ export const StyledMenuItemRightContent = styled.div`
|
||||
`;
|
||||
|
||||
export const StyledHoverableMenuItemBase = styled(StyledMenuItemBase)<{
|
||||
isMenuOpen: boolean;
|
||||
isIconDisplayedOnHoverOnly?: boolean;
|
||||
}>`
|
||||
${({ isIconDisplayedOnHoverOnly, theme }) =>
|
||||
isIconDisplayedOnHoverOnly &&
|
||||
css`
|
||||
& .hoverable-buttons {
|
||||
opacity: 0;
|
||||
position: fixed;
|
||||
right: ${theme.spacing(2)};
|
||||
}
|
||||
|
||||
&:hover {
|
||||
& .hoverable-buttons {
|
||||
opacity: 1;
|
||||
position: static;
|
||||
}
|
||||
}
|
||||
`};
|
||||
|
||||
& .hoverable-buttons {
|
||||
pointer-events: none;
|
||||
position: fixed;
|
||||
right: ${({ theme }) => theme.spacing(2)};
|
||||
opacity: ${({ isIconDisplayedOnHoverOnly }) =>
|
||||
isIconDisplayedOnHoverOnly ? 0 : 1};
|
||||
transition: opacity ${({ theme }) => theme.animation.duration.instant}s ease;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
& .hoverable-buttons {
|
||||
opacity: 1;
|
||||
pointer-events: auto;
|
||||
position: static;
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
Reference in New Issue
Block a user