Feat: Add tooltips on new column menu (#1893)
* implemented tooltip for view fields * console.log
This commit is contained in:
@ -43,6 +43,7 @@ export const companiesAvailableColumnDefinitions: ColumnDefinition<FieldMetadata
|
|||||||
},
|
},
|
||||||
isVisible: true,
|
isVisible: true,
|
||||||
buttonIcon: IconArrowUpRight,
|
buttonIcon: IconArrowUpRight,
|
||||||
|
infoTooltipContent: 'The company name.',
|
||||||
basePathToShowPage: '/companies/',
|
basePathToShowPage: '/companies/',
|
||||||
} satisfies ColumnDefinition<FieldChipMetadata>,
|
} satisfies ColumnDefinition<FieldChipMetadata>,
|
||||||
{
|
{
|
||||||
@ -58,6 +59,8 @@ export const companiesAvailableColumnDefinitions: ColumnDefinition<FieldMetadata
|
|||||||
},
|
},
|
||||||
isVisible: true,
|
isVisible: true,
|
||||||
buttonIcon: IconPencil,
|
buttonIcon: IconPencil,
|
||||||
|
infoTooltipContent:
|
||||||
|
'The company website URL. We use this url to fetch the company icon.',
|
||||||
} satisfies ColumnDefinition<FieldURLMetadata>,
|
} satisfies ColumnDefinition<FieldURLMetadata>,
|
||||||
{
|
{
|
||||||
key: 'accountOwner',
|
key: 'accountOwner',
|
||||||
@ -71,6 +74,8 @@ export const companiesAvailableColumnDefinitions: ColumnDefinition<FieldMetadata
|
|||||||
relationType: Entity.User,
|
relationType: Entity.User,
|
||||||
},
|
},
|
||||||
isVisible: true,
|
isVisible: true,
|
||||||
|
infoTooltipContent:
|
||||||
|
'Your team member responsible for managing the company account.',
|
||||||
} satisfies ColumnDefinition<FieldRelationMetadata>,
|
} satisfies ColumnDefinition<FieldRelationMetadata>,
|
||||||
{
|
{
|
||||||
key: 'createdAt',
|
key: 'createdAt',
|
||||||
@ -83,6 +88,7 @@ export const companiesAvailableColumnDefinitions: ColumnDefinition<FieldMetadata
|
|||||||
fieldName: 'createdAt',
|
fieldName: 'createdAt',
|
||||||
},
|
},
|
||||||
isVisible: true,
|
isVisible: true,
|
||||||
|
infoTooltipContent: "Date when the company's record was created.",
|
||||||
} satisfies ColumnDefinition<FieldDateMetadata>,
|
} satisfies ColumnDefinition<FieldDateMetadata>,
|
||||||
{
|
{
|
||||||
key: 'employees',
|
key: 'employees',
|
||||||
@ -97,6 +103,7 @@ export const companiesAvailableColumnDefinitions: ColumnDefinition<FieldMetadata
|
|||||||
placeHolder: 'Employees',
|
placeHolder: 'Employees',
|
||||||
},
|
},
|
||||||
isVisible: true,
|
isVisible: true,
|
||||||
|
infoTooltipContent: 'Number of employees in the company.',
|
||||||
} satisfies ColumnDefinition<FieldNumberMetadata>,
|
} satisfies ColumnDefinition<FieldNumberMetadata>,
|
||||||
{
|
{
|
||||||
key: 'linkedin',
|
key: 'linkedin',
|
||||||
@ -111,6 +118,7 @@ export const companiesAvailableColumnDefinitions: ColumnDefinition<FieldMetadata
|
|||||||
},
|
},
|
||||||
isVisible: true,
|
isVisible: true,
|
||||||
buttonIcon: IconPencil,
|
buttonIcon: IconPencil,
|
||||||
|
infoTooltipContent: 'The company Linkedin account.',
|
||||||
} satisfies ColumnDefinition<FieldURLMetadata>,
|
} satisfies ColumnDefinition<FieldURLMetadata>,
|
||||||
{
|
{
|
||||||
key: 'address',
|
key: 'address',
|
||||||
@ -124,6 +132,7 @@ export const companiesAvailableColumnDefinitions: ColumnDefinition<FieldMetadata
|
|||||||
placeHolder: 'Address', // Hack: Fake character to prevent password-manager from filling the field
|
placeHolder: 'Address', // Hack: Fake character to prevent password-manager from filling the field
|
||||||
},
|
},
|
||||||
isVisible: true,
|
isVisible: true,
|
||||||
|
infoTooltipContent: 'The company address.',
|
||||||
} satisfies ColumnDefinition<FieldTextMetadata>,
|
} satisfies ColumnDefinition<FieldTextMetadata>,
|
||||||
{
|
{
|
||||||
key: 'idealCustomerProfile',
|
key: 'idealCustomerProfile',
|
||||||
@ -136,6 +145,8 @@ export const companiesAvailableColumnDefinitions: ColumnDefinition<FieldMetadata
|
|||||||
fieldName: 'idealCustomerProfile',
|
fieldName: 'idealCustomerProfile',
|
||||||
},
|
},
|
||||||
isVisible: false,
|
isVisible: false,
|
||||||
|
infoTooltipContent:
|
||||||
|
'Ideal Customer Profile: Indicates whether the company is the most suitable and valuable customer for you.',
|
||||||
} satisfies ColumnDefinition<FieldBooleanMetadata>,
|
} satisfies ColumnDefinition<FieldBooleanMetadata>,
|
||||||
{
|
{
|
||||||
key: 'annualRecurringRevenue',
|
key: 'annualRecurringRevenue',
|
||||||
@ -148,6 +159,8 @@ export const companiesAvailableColumnDefinitions: ColumnDefinition<FieldMetadata
|
|||||||
fieldName: 'annualRecurringRevenue',
|
fieldName: 'annualRecurringRevenue',
|
||||||
placeHolder: 'ARR',
|
placeHolder: 'ARR',
|
||||||
},
|
},
|
||||||
|
infoTooltipContent:
|
||||||
|
'Annual Recurring Revenue: The actual or estimated annual revenue of the company.',
|
||||||
} satisfies ColumnDefinition<FieldMoneyMetadata>,
|
} satisfies ColumnDefinition<FieldMoneyMetadata>,
|
||||||
{
|
{
|
||||||
key: 'xUrl',
|
key: 'xUrl',
|
||||||
@ -162,5 +175,6 @@ export const companiesAvailableColumnDefinitions: ColumnDefinition<FieldMetadata
|
|||||||
},
|
},
|
||||||
isVisible: false,
|
isVisible: false,
|
||||||
buttonIcon: IconPencil,
|
buttonIcon: IconPencil,
|
||||||
|
infoTooltipContent: 'The company Twitter account.',
|
||||||
} satisfies ColumnDefinition<FieldURLMetadata>,
|
} satisfies ColumnDefinition<FieldURLMetadata>,
|
||||||
];
|
];
|
||||||
|
|||||||
@ -42,6 +42,7 @@ export const peopleAvailableColumnDefinitions: ColumnDefinition<FieldMetadata>[]
|
|||||||
entityType: Entity.Person,
|
entityType: Entity.Person,
|
||||||
},
|
},
|
||||||
buttonIcon: IconArrowUpRight,
|
buttonIcon: IconArrowUpRight,
|
||||||
|
infoTooltipContent: 'Contact’s first and last name.',
|
||||||
basePathToShowPage: '/person/',
|
basePathToShowPage: '/person/',
|
||||||
} satisfies ColumnDefinition<FieldDoubleTextChipMetadata>,
|
} satisfies ColumnDefinition<FieldDoubleTextChipMetadata>,
|
||||||
{
|
{
|
||||||
@ -56,6 +57,7 @@ export const peopleAvailableColumnDefinitions: ColumnDefinition<FieldMetadata>[]
|
|||||||
placeHolder: 'Email', // Hack: Fake character to prevent password-manager from filling the field
|
placeHolder: 'Email', // Hack: Fake character to prevent password-manager from filling the field
|
||||||
},
|
},
|
||||||
buttonIcon: IconPencil,
|
buttonIcon: IconPencil,
|
||||||
|
infoTooltipContent: 'Contact’s Email.',
|
||||||
} satisfies ColumnDefinition<FieldEmailMetadata>,
|
} satisfies ColumnDefinition<FieldEmailMetadata>,
|
||||||
{
|
{
|
||||||
key: 'company',
|
key: 'company',
|
||||||
@ -68,6 +70,7 @@ export const peopleAvailableColumnDefinitions: ColumnDefinition<FieldMetadata>[]
|
|||||||
fieldName: 'company',
|
fieldName: 'company',
|
||||||
relationType: Entity.Company,
|
relationType: Entity.Company,
|
||||||
},
|
},
|
||||||
|
infoTooltipContent: 'Contact’s company.',
|
||||||
} satisfies ColumnDefinition<FieldRelationMetadata>,
|
} satisfies ColumnDefinition<FieldRelationMetadata>,
|
||||||
{
|
{
|
||||||
key: 'phone',
|
key: 'phone',
|
||||||
@ -81,6 +84,7 @@ export const peopleAvailableColumnDefinitions: ColumnDefinition<FieldMetadata>[]
|
|||||||
placeHolder: 'Phone', // Hack: Fake character to prevent password-manager from filling the field
|
placeHolder: 'Phone', // Hack: Fake character to prevent password-manager from filling the field
|
||||||
},
|
},
|
||||||
buttonIcon: IconPencil,
|
buttonIcon: IconPencil,
|
||||||
|
infoTooltipContent: 'Contact’s phone number.',
|
||||||
} satisfies ColumnDefinition<FieldPhoneMetadata>,
|
} satisfies ColumnDefinition<FieldPhoneMetadata>,
|
||||||
{
|
{
|
||||||
key: 'createdAt',
|
key: 'createdAt',
|
||||||
@ -92,6 +96,7 @@ export const peopleAvailableColumnDefinitions: ColumnDefinition<FieldMetadata>[]
|
|||||||
metadata: {
|
metadata: {
|
||||||
fieldName: 'createdAt',
|
fieldName: 'createdAt',
|
||||||
},
|
},
|
||||||
|
infoTooltipContent: 'Date when the contact was added.',
|
||||||
} satisfies ColumnDefinition<FieldDateMetadata>,
|
} satisfies ColumnDefinition<FieldDateMetadata>,
|
||||||
{
|
{
|
||||||
key: 'city',
|
key: 'city',
|
||||||
@ -104,6 +109,7 @@ export const peopleAvailableColumnDefinitions: ColumnDefinition<FieldMetadata>[]
|
|||||||
fieldName: 'city',
|
fieldName: 'city',
|
||||||
placeHolder: 'City', // Hack: Fake character to prevent password-manager from filling the field
|
placeHolder: 'City', // Hack: Fake character to prevent password-manager from filling the field
|
||||||
},
|
},
|
||||||
|
infoTooltipContent: 'Contact’s city.',
|
||||||
} satisfies ColumnDefinition<FieldTextMetadata>,
|
} satisfies ColumnDefinition<FieldTextMetadata>,
|
||||||
{
|
{
|
||||||
key: 'jobTitle',
|
key: 'jobTitle',
|
||||||
@ -116,6 +122,7 @@ export const peopleAvailableColumnDefinitions: ColumnDefinition<FieldMetadata>[]
|
|||||||
fieldName: 'jobTitle',
|
fieldName: 'jobTitle',
|
||||||
placeHolder: 'Job title',
|
placeHolder: 'Job title',
|
||||||
},
|
},
|
||||||
|
infoTooltipContent: 'Contact’s job title.',
|
||||||
} satisfies ColumnDefinition<FieldTextMetadata>,
|
} satisfies ColumnDefinition<FieldTextMetadata>,
|
||||||
{
|
{
|
||||||
key: 'linkedin',
|
key: 'linkedin',
|
||||||
@ -129,6 +136,7 @@ export const peopleAvailableColumnDefinitions: ColumnDefinition<FieldMetadata>[]
|
|||||||
placeHolder: 'LinkedIn',
|
placeHolder: 'LinkedIn',
|
||||||
},
|
},
|
||||||
buttonIcon: IconPencil,
|
buttonIcon: IconPencil,
|
||||||
|
infoTooltipContent: 'Contact’s Linkedin account.',
|
||||||
} satisfies ColumnDefinition<FieldURLMetadata>,
|
} satisfies ColumnDefinition<FieldURLMetadata>,
|
||||||
{
|
{
|
||||||
key: 'x',
|
key: 'x',
|
||||||
@ -142,5 +150,6 @@ export const peopleAvailableColumnDefinitions: ColumnDefinition<FieldMetadata>[]
|
|||||||
placeHolder: 'X',
|
placeHolder: 'X',
|
||||||
},
|
},
|
||||||
buttonIcon: IconPencil,
|
buttonIcon: IconPencil,
|
||||||
|
infoTooltipContent: 'Contact’s Twitter account.',
|
||||||
} satisfies ColumnDefinition<FieldURLMetadata>,
|
} satisfies ColumnDefinition<FieldURLMetadata>,
|
||||||
];
|
];
|
||||||
|
|||||||
@ -27,6 +27,8 @@ export const pipelineAvailableFieldDefinitions: BoardFieldDefinition<FieldMetada
|
|||||||
fieldName: 'closeDate',
|
fieldName: 'closeDate',
|
||||||
},
|
},
|
||||||
isVisible: true,
|
isVisible: true,
|
||||||
|
infoTooltipContent:
|
||||||
|
'Specified date by which an opportunity must be completed.',
|
||||||
} satisfies BoardFieldDefinition<FieldDateMetadata>,
|
} satisfies BoardFieldDefinition<FieldDateMetadata>,
|
||||||
{
|
{
|
||||||
key: 'amount',
|
key: 'amount',
|
||||||
@ -39,6 +41,7 @@ export const pipelineAvailableFieldDefinitions: BoardFieldDefinition<FieldMetada
|
|||||||
placeHolder: '0',
|
placeHolder: '0',
|
||||||
},
|
},
|
||||||
isVisible: true,
|
isVisible: true,
|
||||||
|
infoTooltipContent: 'Potential monetary value of a business opportunity.',
|
||||||
} satisfies BoardFieldDefinition<FieldNumberMetadata>,
|
} satisfies BoardFieldDefinition<FieldNumberMetadata>,
|
||||||
{
|
{
|
||||||
key: 'probability',
|
key: 'probability',
|
||||||
@ -50,6 +53,8 @@ export const pipelineAvailableFieldDefinitions: BoardFieldDefinition<FieldMetada
|
|||||||
fieldName: 'probability',
|
fieldName: 'probability',
|
||||||
},
|
},
|
||||||
isVisible: true,
|
isVisible: true,
|
||||||
|
infoTooltipContent:
|
||||||
|
"Level of certainty in the lead's potential to convert into a success.",
|
||||||
} satisfies BoardFieldDefinition<FieldProbabilityMetadata>,
|
} satisfies BoardFieldDefinition<FieldProbabilityMetadata>,
|
||||||
{
|
{
|
||||||
key: 'pointOfContact',
|
key: 'pointOfContact',
|
||||||
@ -64,5 +69,6 @@ export const pipelineAvailableFieldDefinitions: BoardFieldDefinition<FieldMetada
|
|||||||
},
|
},
|
||||||
isVisible: true,
|
isVisible: true,
|
||||||
buttonIcon: IconPencil,
|
buttonIcon: IconPencil,
|
||||||
|
infoTooltipContent: 'Primary contact within the company.',
|
||||||
} satisfies BoardFieldDefinition<FieldRelationMetadata>,
|
} satisfies BoardFieldDefinition<FieldRelationMetadata>,
|
||||||
];
|
];
|
||||||
|
|||||||
@ -21,17 +21,21 @@ export type FloatingIconButtonProps = {
|
|||||||
disabled?: boolean;
|
disabled?: boolean;
|
||||||
focus?: boolean;
|
focus?: boolean;
|
||||||
onClick?: (event: React.MouseEvent<HTMLButtonElement>) => void;
|
onClick?: (event: React.MouseEvent<HTMLButtonElement>) => void;
|
||||||
|
isActive?: boolean;
|
||||||
};
|
};
|
||||||
|
|
||||||
const StyledButton = styled.button<
|
const StyledButton = styled.button<
|
||||||
Pick<
|
Pick<
|
||||||
FloatingIconButtonProps,
|
FloatingIconButtonProps,
|
||||||
'size' | 'position' | 'applyShadow' | 'applyBlur' | 'focus'
|
'size' | 'position' | 'applyShadow' | 'applyBlur' | 'focus' | 'isActive'
|
||||||
>
|
>
|
||||||
>`
|
>`
|
||||||
align-items: center;
|
align-items: center;
|
||||||
backdrop-filter: ${({ applyBlur }) => (applyBlur ? 'blur(20px)' : 'none')};
|
backdrop-filter: ${({ applyBlur }) => (applyBlur ? 'blur(20px)' : 'none')};
|
||||||
background: ${({ theme }) => theme.background.primary};
|
background: ${({ theme, isActive }) =>
|
||||||
|
!!isActive
|
||||||
|
? theme.background.transparent.medium
|
||||||
|
: theme.background.primary};
|
||||||
border: ${({ focus, theme }) =>
|
border: ${({ focus, theme }) =>
|
||||||
focus ? `1px solid ${theme.color.blue}` : 'transparent'};
|
focus ? `1px solid ${theme.color.blue}` : 'transparent'};
|
||||||
border-radius: ${({ position, theme }) => {
|
border-radius: ${({ position, theme }) => {
|
||||||
@ -87,7 +91,8 @@ const StyledButton = styled.button<
|
|||||||
}}
|
}}
|
||||||
|
|
||||||
&:hover {
|
&:hover {
|
||||||
background: ${({ theme }) => theme.background.transparent.lighter};
|
background: ${({ theme, isActive }) =>
|
||||||
|
!!isActive ?? theme.background.transparent.lighter};
|
||||||
}
|
}
|
||||||
|
|
||||||
&:active {
|
&:active {
|
||||||
@ -110,6 +115,7 @@ export const FloatingIconButton = ({
|
|||||||
disabled = false,
|
disabled = false,
|
||||||
focus = false,
|
focus = false,
|
||||||
onClick,
|
onClick,
|
||||||
|
isActive,
|
||||||
}: FloatingIconButtonProps) => {
|
}: FloatingIconButtonProps) => {
|
||||||
const theme = useTheme();
|
const theme = useTheme();
|
||||||
return (
|
return (
|
||||||
@ -122,6 +128,7 @@ export const FloatingIconButton = ({
|
|||||||
className={className}
|
className={className}
|
||||||
position={position}
|
position={position}
|
||||||
onClick={onClick}
|
onClick={onClick}
|
||||||
|
isActive={isActive}
|
||||||
>
|
>
|
||||||
{Icon && <Icon size={theme.icon.size.md} />}
|
{Icon && <Icon size={theme.icon.size.md} />}
|
||||||
</StyledButton>
|
</StyledButton>
|
||||||
|
|||||||
@ -27,15 +27,17 @@ export type FloatingIconButtonGroupProps = Pick<
|
|||||||
iconButtons: {
|
iconButtons: {
|
||||||
Icon: IconComponent;
|
Icon: IconComponent;
|
||||||
onClick?: (event: MouseEvent<any>) => void;
|
onClick?: (event: MouseEvent<any>) => void;
|
||||||
|
isActive?: boolean;
|
||||||
}[];
|
}[];
|
||||||
};
|
};
|
||||||
|
|
||||||
export const FloatingIconButtonGroup = ({
|
export const FloatingIconButtonGroup = ({
|
||||||
iconButtons,
|
iconButtons,
|
||||||
size,
|
size,
|
||||||
|
className,
|
||||||
}: FloatingIconButtonGroupProps) => (
|
}: FloatingIconButtonGroupProps) => (
|
||||||
<StyledFloatingIconButtonGroupContainer>
|
<StyledFloatingIconButtonGroupContainer className={className}>
|
||||||
{iconButtons.map(({ Icon, onClick }, index) => {
|
{iconButtons.map(({ Icon, onClick, isActive }, index) => {
|
||||||
const position: FloatingIconButtonPosition =
|
const position: FloatingIconButtonPosition =
|
||||||
iconButtons.length === 1
|
iconButtons.length === 1
|
||||||
? 'standalone'
|
? 'standalone'
|
||||||
@ -54,6 +56,7 @@ export const FloatingIconButtonGroup = ({
|
|||||||
onClick={onClick}
|
onClick={onClick}
|
||||||
position={position}
|
position={position}
|
||||||
size={size}
|
size={size}
|
||||||
|
isActive={isActive}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
})}
|
})}
|
||||||
|
|||||||
@ -11,4 +11,5 @@ export type FieldDefinition<T extends FieldMetadata> = {
|
|||||||
metadata: T;
|
metadata: T;
|
||||||
buttonIcon?: IconComponent;
|
buttonIcon?: IconComponent;
|
||||||
basePathToShowPage?: string;
|
basePathToShowPage?: string;
|
||||||
|
infoTooltipContent?: string;
|
||||||
};
|
};
|
||||||
|
|||||||
@ -20,6 +20,7 @@ export type MenuItemProps = {
|
|||||||
accent?: MenuItemAccent;
|
accent?: MenuItemAccent;
|
||||||
text: string;
|
text: string;
|
||||||
iconButtons?: MenuItemIconButton[];
|
iconButtons?: MenuItemIconButton[];
|
||||||
|
isTooltipOpen?: boolean;
|
||||||
className?: string;
|
className?: string;
|
||||||
testId?: string;
|
testId?: string;
|
||||||
onClick?: () => void;
|
onClick?: () => void;
|
||||||
@ -30,6 +31,7 @@ export const MenuItem = ({
|
|||||||
accent = 'default',
|
accent = 'default',
|
||||||
text,
|
text,
|
||||||
iconButtons,
|
iconButtons,
|
||||||
|
isTooltipOpen,
|
||||||
className,
|
className,
|
||||||
testId,
|
testId,
|
||||||
onClick,
|
onClick,
|
||||||
@ -42,6 +44,7 @@ export const MenuItem = ({
|
|||||||
onClick={onClick}
|
onClick={onClick}
|
||||||
className={className}
|
className={className}
|
||||||
accent={accent}
|
accent={accent}
|
||||||
|
isMenuOpen={!!isTooltipOpen}
|
||||||
>
|
>
|
||||||
<StyledMenuItemLeftContent>
|
<StyledMenuItemLeftContent>
|
||||||
<MenuItemLeftContent LeftIcon={LeftIcon ?? undefined} text={text} />
|
<MenuItemLeftContent LeftIcon={LeftIcon ?? undefined} text={text} />
|
||||||
|
|||||||
@ -11,6 +11,7 @@ export type MenuItemDraggableProps = {
|
|||||||
LeftIcon: IconComponent | undefined;
|
LeftIcon: IconComponent | undefined;
|
||||||
accent?: MenuItemAccent;
|
accent?: MenuItemAccent;
|
||||||
iconButtons?: MenuItemIconButton[];
|
iconButtons?: MenuItemIconButton[];
|
||||||
|
isTooltipOpen?: boolean;
|
||||||
onClick?: () => void;
|
onClick?: () => void;
|
||||||
text: string;
|
text: string;
|
||||||
isDragDisabled?: boolean;
|
isDragDisabled?: boolean;
|
||||||
@ -20,6 +21,7 @@ export const MenuItemDraggable = ({
|
|||||||
LeftIcon,
|
LeftIcon,
|
||||||
accent = 'default',
|
accent = 'default',
|
||||||
iconButtons,
|
iconButtons,
|
||||||
|
isTooltipOpen,
|
||||||
onClick,
|
onClick,
|
||||||
text,
|
text,
|
||||||
isDragDisabled = false,
|
isDragDisabled = false,
|
||||||
@ -32,17 +34,19 @@ export const MenuItemDraggable = ({
|
|||||||
onClick={onClick}
|
onClick={onClick}
|
||||||
accent={accent}
|
accent={accent}
|
||||||
className={className}
|
className={className}
|
||||||
|
isMenuOpen={!!isTooltipOpen}
|
||||||
>
|
>
|
||||||
<MenuItemLeftContent
|
<MenuItemLeftContent
|
||||||
LeftIcon={LeftIcon}
|
LeftIcon={LeftIcon}
|
||||||
text={text}
|
text={text}
|
||||||
showGrip={!isDragDisabled}
|
showGrip={!isDragDisabled}
|
||||||
/>
|
/>
|
||||||
<div className="hoverable-buttons">
|
{showIconButtons && (
|
||||||
{showIconButtons && (
|
<FloatingIconButtonGroup
|
||||||
<FloatingIconButtonGroup iconButtons={iconButtons} />
|
className="hoverable-buttons"
|
||||||
)}
|
iconButtons={iconButtons}
|
||||||
</div>
|
/>
|
||||||
|
)}
|
||||||
</StyledHoverableMenuItemBase>
|
</StyledHoverableMenuItemBase>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@ -89,9 +89,11 @@ export const StyledMenuItemRightContent = styled.div`
|
|||||||
flex-direction: row;
|
flex-direction: row;
|
||||||
`;
|
`;
|
||||||
|
|
||||||
export const StyledHoverableMenuItemBase = styled(StyledMenuItemBase)`
|
export const StyledHoverableMenuItemBase = styled(StyledMenuItemBase)<{
|
||||||
|
isMenuOpen: boolean;
|
||||||
|
}>`
|
||||||
& .hoverable-buttons {
|
& .hoverable-buttons {
|
||||||
opacity: 0;
|
opacity: ${({ isMenuOpen }) => (isMenuOpen ? 1 : 0)};
|
||||||
pointer-events: none;
|
pointer-events: none;
|
||||||
position: fixed;
|
position: fixed;
|
||||||
right: ${({ theme }) => theme.spacing(2)};
|
right: ${({ theme }) => theme.spacing(2)};
|
||||||
|
|||||||
@ -1,3 +1,5 @@
|
|||||||
|
import { useRef, useState } from 'react';
|
||||||
|
import { createPortal } from 'react-dom';
|
||||||
import {
|
import {
|
||||||
DropResult,
|
DropResult,
|
||||||
OnDragEndResponder,
|
OnDragEndResponder,
|
||||||
@ -9,8 +11,12 @@ import { DraggableList } from '@/ui/draggable-list/components/DraggableList';
|
|||||||
import { StyledDropdownMenuItemsContainer } from '@/ui/dropdown/components/StyledDropdownMenuItemsContainer';
|
import { StyledDropdownMenuItemsContainer } from '@/ui/dropdown/components/StyledDropdownMenuItemsContainer';
|
||||||
import { StyledDropdownMenuSubheader } from '@/ui/dropdown/components/StyledDropdownMenuSubheader';
|
import { StyledDropdownMenuSubheader } from '@/ui/dropdown/components/StyledDropdownMenuSubheader';
|
||||||
import { IconMinus, IconPlus } from '@/ui/icon';
|
import { IconMinus, IconPlus } from '@/ui/icon';
|
||||||
|
import { IconInfoCircle } from '@/ui/input/constants/icons';
|
||||||
import { MenuItem } from '@/ui/menu-item/components/MenuItem';
|
import { MenuItem } from '@/ui/menu-item/components/MenuItem';
|
||||||
import { MenuItemDraggable } from '@/ui/menu-item/components/MenuItemDraggable';
|
import { MenuItemDraggable } from '@/ui/menu-item/components/MenuItemDraggable';
|
||||||
|
import { AppTooltip } from '@/ui/tooltip/AppTooltip';
|
||||||
|
import { useListenClickOutside } from '@/ui/utilities/pointer-event/hooks/useListenClickOutside';
|
||||||
|
import { isDefined } from '~/utils/isDefined';
|
||||||
|
|
||||||
import { ViewFieldForVisibility } from '../types/ViewFieldForVisibility';
|
import { ViewFieldForVisibility } from '../types/ViewFieldForVisibility';
|
||||||
|
|
||||||
@ -33,8 +39,38 @@ export const ViewFieldsVisibilityDropdownSection = ({
|
|||||||
onDragEnd?.(result, provided);
|
onDragEnd?.(result, provided);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const [openToolTipIndex, setOpenToolTipIndex] = useState<number>();
|
||||||
|
|
||||||
|
const handleInfoButtonClick = (index: number) => {
|
||||||
|
if (index === openToolTipIndex) setOpenToolTipIndex(undefined);
|
||||||
|
else setOpenToolTipIndex(index);
|
||||||
|
};
|
||||||
|
|
||||||
const getIconButtons = (index: number, field: ViewFieldForVisibility) => {
|
const getIconButtons = (index: number, field: ViewFieldForVisibility) => {
|
||||||
if (index !== 0) {
|
const isFirstColumn = isDraggable && index === 0;
|
||||||
|
if (isFirstColumn && field.infoTooltipContent) {
|
||||||
|
return [
|
||||||
|
{
|
||||||
|
Icon: IconInfoCircle,
|
||||||
|
onClick: () => handleInfoButtonClick(index),
|
||||||
|
isActive: openToolTipIndex === index,
|
||||||
|
},
|
||||||
|
];
|
||||||
|
}
|
||||||
|
if (!isFirstColumn && field.infoTooltipContent) {
|
||||||
|
return [
|
||||||
|
{
|
||||||
|
Icon: IconInfoCircle,
|
||||||
|
onClick: () => handleInfoButtonClick(index),
|
||||||
|
isActive: openToolTipIndex === index,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Icon: field.isVisible ? IconMinus : IconPlus,
|
||||||
|
onClick: () => onVisibilityChange(field),
|
||||||
|
},
|
||||||
|
];
|
||||||
|
}
|
||||||
|
if (!isFirstColumn && !field.infoTooltipContent) {
|
||||||
return [
|
return [
|
||||||
{
|
{
|
||||||
Icon: field.isVisible ? IconMinus : IconPlus,
|
Icon: field.isVisible ? IconMinus : IconPlus,
|
||||||
@ -44,11 +80,20 @@ export const ViewFieldsVisibilityDropdownSection = ({
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const ref = useRef<HTMLDivElement>(null);
|
||||||
|
|
||||||
|
useListenClickOutside({
|
||||||
|
refs: [ref],
|
||||||
|
callback: () => {
|
||||||
|
setOpenToolTipIndex(undefined);
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<div ref={ref}>
|
||||||
<StyledDropdownMenuSubheader>{title}</StyledDropdownMenuSubheader>
|
<StyledDropdownMenuSubheader>{title}</StyledDropdownMenuSubheader>
|
||||||
<StyledDropdownMenuItemsContainer>
|
<StyledDropdownMenuItemsContainer>
|
||||||
{isDraggable && (
|
{isDraggable ? (
|
||||||
<DraggableList
|
<DraggableList
|
||||||
onDragEnd={handleOnDrag}
|
onDragEnd={handleOnDrag}
|
||||||
draggableItems={
|
draggableItems={
|
||||||
@ -64,8 +109,10 @@ export const ViewFieldsVisibilityDropdownSection = ({
|
|||||||
key={field.key}
|
key={field.key}
|
||||||
LeftIcon={field.Icon}
|
LeftIcon={field.Icon}
|
||||||
iconButtons={getIconButtons(index, field)}
|
iconButtons={getIconButtons(index, field)}
|
||||||
|
isTooltipOpen={openToolTipIndex === index}
|
||||||
text={field.name}
|
text={field.name}
|
||||||
isDragDisabled={index === 0}
|
isDragDisabled={index === 0}
|
||||||
|
className={`${title}-draggable-item-tooltip-anchor-${index}`}
|
||||||
/>
|
/>
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
@ -73,22 +120,31 @@ export const ViewFieldsVisibilityDropdownSection = ({
|
|||||||
</>
|
</>
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
)}
|
) : (
|
||||||
{!isDraggable &&
|
fields.map((field, index) => (
|
||||||
fields.map((field) => (
|
|
||||||
<MenuItem
|
<MenuItem
|
||||||
key={field.key}
|
key={field.key}
|
||||||
LeftIcon={field.Icon}
|
LeftIcon={field.Icon}
|
||||||
iconButtons={[
|
iconButtons={getIconButtons(index, field)}
|
||||||
{
|
isTooltipOpen={openToolTipIndex === index}
|
||||||
Icon: field.isVisible ? IconMinus : IconPlus,
|
|
||||||
onClick: () => onVisibilityChange(field),
|
|
||||||
},
|
|
||||||
]}
|
|
||||||
text={field.name}
|
text={field.name}
|
||||||
|
className={`${title}-fixed-item-tooltip-anchor-${index}`}
|
||||||
/>
|
/>
|
||||||
))}
|
))
|
||||||
|
)}
|
||||||
</StyledDropdownMenuItemsContainer>
|
</StyledDropdownMenuItemsContainer>
|
||||||
</>
|
{isDefined(openToolTipIndex) &&
|
||||||
|
createPortal(
|
||||||
|
<AppTooltip
|
||||||
|
anchorSelect={`.${title}-${
|
||||||
|
isDraggable ? 'draggable' : 'fixed'
|
||||||
|
}-item-tooltip-anchor-${openToolTipIndex}`}
|
||||||
|
place="left"
|
||||||
|
content={fields[openToolTipIndex].infoTooltipContent}
|
||||||
|
isOpen={true}
|
||||||
|
/>,
|
||||||
|
document.body,
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@ -3,7 +3,7 @@ import { FieldMetadata } from '@/ui/field/types/FieldMetadata';
|
|||||||
|
|
||||||
export type ViewFieldForVisibility = Pick<
|
export type ViewFieldForVisibility = Pick<
|
||||||
FieldDefinition<FieldMetadata>,
|
FieldDefinition<FieldMetadata>,
|
||||||
'key' | 'name' | 'Icon'
|
'key' | 'name' | 'Icon' | 'infoTooltipContent'
|
||||||
> & {
|
> & {
|
||||||
isVisible?: boolean;
|
isVisible?: boolean;
|
||||||
index: number;
|
index: number;
|
||||||
|
|||||||
Reference in New Issue
Block a user