Feat: First column style update (#1746)
reimplemented as per suggestions by lucas
This commit is contained in:
@ -1,5 +1,5 @@
|
|||||||
import { ActivityTargetChips } from '@/activities/components/ActivityTargetChips';
|
import { ActivityTargetChips } from '@/activities/components/ActivityTargetChips';
|
||||||
import { IconArrowUpRight } from '@/ui/icon';
|
import { IconArrowUpRight, IconPencil } from '@/ui/icon';
|
||||||
import { InlineCellContainer } from '@/ui/inline-cell/components/InlineCellContainer';
|
import { InlineCellContainer } from '@/ui/inline-cell/components/InlineCellContainer';
|
||||||
import { FieldRecoilScopeContext } from '@/ui/inline-cell/states/recoil-scope-contexts/FieldRecoilScopeContext';
|
import { FieldRecoilScopeContext } from '@/ui/inline-cell/states/recoil-scope-contexts/FieldRecoilScopeContext';
|
||||||
import { RelationPickerHotkeyScope } from '@/ui/input/relation-picker/types/RelationPickerHotkeyScope';
|
import { RelationPickerHotkeyScope } from '@/ui/input/relation-picker/types/RelationPickerHotkeyScope';
|
||||||
@ -24,7 +24,7 @@ export const ActivityRelationEditableField = ({ activity }: OwnProps) => {
|
|||||||
<RecoilScope CustomRecoilScopeContext={FieldRecoilScopeContext}>
|
<RecoilScope CustomRecoilScopeContext={FieldRecoilScopeContext}>
|
||||||
<RecoilScope>
|
<RecoilScope>
|
||||||
<InlineCellContainer
|
<InlineCellContainer
|
||||||
useEditButton
|
buttonIcon={IconPencil}
|
||||||
customEditHotkeyScope={{
|
customEditHotkeyScope={{
|
||||||
scope: RelationPickerHotkeyScope.RelationPicker,
|
scope: RelationPickerHotkeyScope.RelationPicker,
|
||||||
}}
|
}}
|
||||||
|
|||||||
@ -169,7 +169,7 @@ export const CompanyBoardCard = () => {
|
|||||||
Icon: viewField.Icon,
|
Icon: viewField.Icon,
|
||||||
type: viewField.type,
|
type: viewField.type,
|
||||||
metadata: viewField.metadata,
|
metadata: viewField.metadata,
|
||||||
useEditButton: viewField.useEditButton,
|
buttonIcon: viewField.buttonIcon,
|
||||||
},
|
},
|
||||||
useUpdateEntityMutation: useUpdateOnePipelineProgressMutation,
|
useUpdateEntityMutation: useUpdateOnePipelineProgressMutation,
|
||||||
hotkeyScope: InlineCellHotkeyScope.InlineCell,
|
hotkeyScope: InlineCellHotkeyScope.InlineCell,
|
||||||
|
|||||||
@ -10,6 +10,7 @@ import {
|
|||||||
FieldURLMetadata,
|
FieldURLMetadata,
|
||||||
} from '@/ui/field/types/FieldMetadata';
|
} from '@/ui/field/types/FieldMetadata';
|
||||||
import {
|
import {
|
||||||
|
IconArrowUpRight,
|
||||||
IconBrandLinkedin,
|
IconBrandLinkedin,
|
||||||
IconBrandX,
|
IconBrandX,
|
||||||
IconBuildingSkyscraper,
|
IconBuildingSkyscraper,
|
||||||
@ -17,6 +18,7 @@ import {
|
|||||||
IconLink,
|
IconLink,
|
||||||
IconMap,
|
IconMap,
|
||||||
IconMoneybag,
|
IconMoneybag,
|
||||||
|
IconPencil,
|
||||||
IconTarget,
|
IconTarget,
|
||||||
IconUserCircle,
|
IconUserCircle,
|
||||||
IconUsers,
|
IconUsers,
|
||||||
@ -40,6 +42,8 @@ export const companiesAvailableColumnDefinitions: ColumnDefinition<FieldMetadata
|
|||||||
placeHolder: 'Company Name',
|
placeHolder: 'Company Name',
|
||||||
},
|
},
|
||||||
isVisible: true,
|
isVisible: true,
|
||||||
|
buttonIcon: IconArrowUpRight,
|
||||||
|
basePathToShowPage: '/companies/',
|
||||||
} satisfies ColumnDefinition<FieldChipMetadata>,
|
} satisfies ColumnDefinition<FieldChipMetadata>,
|
||||||
{
|
{
|
||||||
key: 'domainName',
|
key: 'domainName',
|
||||||
@ -53,7 +57,7 @@ export const companiesAvailableColumnDefinitions: ColumnDefinition<FieldMetadata
|
|||||||
placeHolder: 'example.com',
|
placeHolder: 'example.com',
|
||||||
},
|
},
|
||||||
isVisible: true,
|
isVisible: true,
|
||||||
useEditButton: true,
|
buttonIcon: IconPencil,
|
||||||
} satisfies ColumnDefinition<FieldURLMetadata>,
|
} satisfies ColumnDefinition<FieldURLMetadata>,
|
||||||
{
|
{
|
||||||
key: 'accountOwner',
|
key: 'accountOwner',
|
||||||
@ -106,7 +110,7 @@ export const companiesAvailableColumnDefinitions: ColumnDefinition<FieldMetadata
|
|||||||
placeHolder: 'LinkedIn URL',
|
placeHolder: 'LinkedIn URL',
|
||||||
},
|
},
|
||||||
isVisible: true,
|
isVisible: true,
|
||||||
useEditButton: true,
|
buttonIcon: IconPencil,
|
||||||
} satisfies ColumnDefinition<FieldURLMetadata>,
|
} satisfies ColumnDefinition<FieldURLMetadata>,
|
||||||
{
|
{
|
||||||
key: 'address',
|
key: 'address',
|
||||||
@ -157,6 +161,6 @@ export const companiesAvailableColumnDefinitions: ColumnDefinition<FieldMetadata
|
|||||||
placeHolder: 'X',
|
placeHolder: 'X',
|
||||||
},
|
},
|
||||||
isVisible: false,
|
isVisible: false,
|
||||||
useEditButton: true,
|
buttonIcon: IconPencil,
|
||||||
} satisfies ColumnDefinition<FieldURLMetadata>,
|
} satisfies ColumnDefinition<FieldURLMetadata>,
|
||||||
];
|
];
|
||||||
|
|||||||
@ -9,6 +9,7 @@ import {
|
|||||||
FieldURLMetadata,
|
FieldURLMetadata,
|
||||||
} from '@/ui/field/types/FieldMetadata';
|
} from '@/ui/field/types/FieldMetadata';
|
||||||
import {
|
import {
|
||||||
|
IconArrowUpRight,
|
||||||
IconBrandLinkedin,
|
IconBrandLinkedin,
|
||||||
IconBrandX,
|
IconBrandX,
|
||||||
IconBriefcase,
|
IconBriefcase,
|
||||||
@ -16,6 +17,7 @@ import {
|
|||||||
IconCalendarEvent,
|
IconCalendarEvent,
|
||||||
IconMail,
|
IconMail,
|
||||||
IconMap,
|
IconMap,
|
||||||
|
IconPencil,
|
||||||
IconPhone,
|
IconPhone,
|
||||||
IconUser,
|
IconUser,
|
||||||
} from '@/ui/icon/index';
|
} from '@/ui/icon/index';
|
||||||
@ -39,6 +41,8 @@ export const peopleAvailableColumnDefinitions: ColumnDefinition<FieldMetadata>[]
|
|||||||
avatarUrlFieldName: 'avatarUrl',
|
avatarUrlFieldName: 'avatarUrl',
|
||||||
entityType: Entity.Person,
|
entityType: Entity.Person,
|
||||||
},
|
},
|
||||||
|
buttonIcon: IconArrowUpRight,
|
||||||
|
basePathToShowPage: '/person/',
|
||||||
} satisfies ColumnDefinition<FieldDoubleTextChipMetadata>,
|
} satisfies ColumnDefinition<FieldDoubleTextChipMetadata>,
|
||||||
{
|
{
|
||||||
key: 'email',
|
key: 'email',
|
||||||
@ -51,7 +55,7 @@ export const peopleAvailableColumnDefinitions: ColumnDefinition<FieldMetadata>[]
|
|||||||
fieldName: 'email',
|
fieldName: 'email',
|
||||||
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
|
||||||
},
|
},
|
||||||
useEditButton: true,
|
buttonIcon: IconPencil,
|
||||||
} satisfies ColumnDefinition<FieldEmailMetadata>,
|
} satisfies ColumnDefinition<FieldEmailMetadata>,
|
||||||
{
|
{
|
||||||
key: 'company',
|
key: 'company',
|
||||||
@ -76,7 +80,7 @@ export const peopleAvailableColumnDefinitions: ColumnDefinition<FieldMetadata>[]
|
|||||||
fieldName: 'phone',
|
fieldName: 'phone',
|
||||||
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
|
||||||
},
|
},
|
||||||
useEditButton: true,
|
buttonIcon: IconPencil,
|
||||||
} satisfies ColumnDefinition<FieldPhoneMetadata>,
|
} satisfies ColumnDefinition<FieldPhoneMetadata>,
|
||||||
{
|
{
|
||||||
key: 'createdAt',
|
key: 'createdAt',
|
||||||
@ -124,7 +128,7 @@ export const peopleAvailableColumnDefinitions: ColumnDefinition<FieldMetadata>[]
|
|||||||
fieldName: 'linkedinUrl',
|
fieldName: 'linkedinUrl',
|
||||||
placeHolder: 'LinkedIn',
|
placeHolder: 'LinkedIn',
|
||||||
},
|
},
|
||||||
useEditButton: true,
|
buttonIcon: IconPencil,
|
||||||
} satisfies ColumnDefinition<FieldURLMetadata>,
|
} satisfies ColumnDefinition<FieldURLMetadata>,
|
||||||
{
|
{
|
||||||
key: 'x',
|
key: 'x',
|
||||||
@ -137,6 +141,6 @@ export const peopleAvailableColumnDefinitions: ColumnDefinition<FieldMetadata>[]
|
|||||||
fieldName: 'xUrl',
|
fieldName: 'xUrl',
|
||||||
placeHolder: 'X',
|
placeHolder: 'X',
|
||||||
},
|
},
|
||||||
useEditButton: true,
|
buttonIcon: IconPencil,
|
||||||
} satisfies ColumnDefinition<FieldURLMetadata>,
|
} satisfies ColumnDefinition<FieldURLMetadata>,
|
||||||
];
|
];
|
||||||
|
|||||||
@ -9,6 +9,7 @@ import {
|
|||||||
import {
|
import {
|
||||||
IconCalendarEvent,
|
IconCalendarEvent,
|
||||||
IconCurrencyDollar,
|
IconCurrencyDollar,
|
||||||
|
IconPencil,
|
||||||
IconProgressCheck,
|
IconProgressCheck,
|
||||||
IconUser,
|
IconUser,
|
||||||
} from '@/ui/icon';
|
} from '@/ui/icon';
|
||||||
@ -62,6 +63,6 @@ export const pipelineAvailableFieldDefinitions: BoardFieldDefinition<FieldMetada
|
|||||||
useEditButton: true,
|
useEditButton: true,
|
||||||
},
|
},
|
||||||
isVisible: true,
|
isVisible: true,
|
||||||
useEditButton: true,
|
buttonIcon: IconPencil,
|
||||||
} satisfies BoardFieldDefinition<FieldRelationMetadata>,
|
} satisfies BoardFieldDefinition<FieldRelationMetadata>,
|
||||||
];
|
];
|
||||||
|
|||||||
@ -2,7 +2,9 @@ import { selectorFamily } from 'recoil';
|
|||||||
|
|
||||||
import { FieldDefinition } from '../../types/FieldDefinition';
|
import { FieldDefinition } from '../../types/FieldDefinition';
|
||||||
import { FieldMetadata } from '../../types/FieldMetadata';
|
import { FieldMetadata } from '../../types/FieldMetadata';
|
||||||
|
import { isFieldChip } from '../../types/guards/isFieldChip';
|
||||||
import { isFieldDate } from '../../types/guards/isFieldDate';
|
import { isFieldDate } from '../../types/guards/isFieldDate';
|
||||||
|
import { isFieldDoubleTextChip } from '../../types/guards/isFieldDoubleTextChip';
|
||||||
import { isFieldEmail } from '../../types/guards/isFieldEmail';
|
import { isFieldEmail } from '../../types/guards/isFieldEmail';
|
||||||
import { isFieldMoney } from '../../types/guards/isFieldMoney';
|
import { isFieldMoney } from '../../types/guards/isFieldMoney';
|
||||||
import { isFieldNumber } from '../../types/guards/isFieldNumber';
|
import { isFieldNumber } from '../../types/guards/isFieldNumber';
|
||||||
@ -51,6 +53,41 @@ export const isEntityFieldEmptyFamilySelector = selectorFamily({
|
|||||||
if (isFieldRelationValue(fieldValue)) {
|
if (isFieldRelationValue(fieldValue)) {
|
||||||
return fieldValue === null || fieldValue === undefined;
|
return fieldValue === null || fieldValue === undefined;
|
||||||
}
|
}
|
||||||
|
} else if (isFieldChip(fieldDefinition)) {
|
||||||
|
const contentFieldName = fieldDefinition.metadata.contentFieldName;
|
||||||
|
|
||||||
|
const contentFieldValue = get(entityFieldsFamilyState(entityId))?.[
|
||||||
|
contentFieldName
|
||||||
|
] as string | null;
|
||||||
|
|
||||||
|
return (
|
||||||
|
contentFieldValue === null ||
|
||||||
|
contentFieldValue === undefined ||
|
||||||
|
contentFieldValue === ''
|
||||||
|
);
|
||||||
|
} else if (isFieldDoubleTextChip(fieldDefinition)) {
|
||||||
|
const firstValueFieldName =
|
||||||
|
fieldDefinition.metadata.firstValueFieldName;
|
||||||
|
|
||||||
|
const secondValueFieldName =
|
||||||
|
fieldDefinition.metadata.secondValueFieldName;
|
||||||
|
|
||||||
|
const contentFieldFirstValue = get(entityFieldsFamilyState(entityId))?.[
|
||||||
|
firstValueFieldName
|
||||||
|
] as string | null;
|
||||||
|
|
||||||
|
const contentFieldSecondValue = get(
|
||||||
|
entityFieldsFamilyState(entityId),
|
||||||
|
)?.[secondValueFieldName] as string | null;
|
||||||
|
|
||||||
|
return (
|
||||||
|
(contentFieldFirstValue === null ||
|
||||||
|
contentFieldFirstValue === undefined ||
|
||||||
|
contentFieldFirstValue === '') &&
|
||||||
|
(contentFieldSecondValue === null ||
|
||||||
|
contentFieldSecondValue === undefined ||
|
||||||
|
contentFieldSecondValue === '')
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
|
|||||||
@ -9,5 +9,6 @@ export type FieldDefinition<T extends FieldMetadata> = {
|
|||||||
Icon?: IconComponent;
|
Icon?: IconComponent;
|
||||||
type: FieldType;
|
type: FieldType;
|
||||||
metadata: T;
|
metadata: T;
|
||||||
useEditButton?: boolean;
|
buttonIcon?: IconComponent;
|
||||||
|
basePathToShowPage?: string;
|
||||||
};
|
};
|
||||||
|
|||||||
@ -57,7 +57,7 @@ export const InlineCell = () => {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<InlineCellContainer
|
<InlineCellContainer
|
||||||
useEditButton={fieldDefinition.useEditButton}
|
buttonIcon={fieldDefinition.buttonIcon}
|
||||||
customEditHotkeyScope={
|
customEditHotkeyScope={
|
||||||
isFieldRelation(fieldDefinition)
|
isFieldRelation(fieldDefinition)
|
||||||
? {
|
? {
|
||||||
|
|||||||
@ -9,7 +9,7 @@ import { HotkeyScope } from '@/ui/utilities/hotkey/types/HotkeyScope';
|
|||||||
import { useInlineCell } from '../hooks/useInlineCell';
|
import { useInlineCell } from '../hooks/useInlineCell';
|
||||||
|
|
||||||
import { InlineCellDisplayMode } from './InlineCellDisplayMode';
|
import { InlineCellDisplayMode } from './InlineCellDisplayMode';
|
||||||
import { InlineCellEditButton } from './InlineCellEditButton';
|
import { InlineCellButton } from './InlineCellEditButton';
|
||||||
import { InlineCellEditMode } from './InlineCellEditMode';
|
import { InlineCellEditMode } from './InlineCellEditMode';
|
||||||
|
|
||||||
const StyledIconContainer = styled.div`
|
const StyledIconContainer = styled.div`
|
||||||
@ -76,7 +76,7 @@ type OwnProps = {
|
|||||||
IconLabel?: IconComponent;
|
IconLabel?: IconComponent;
|
||||||
label?: string;
|
label?: string;
|
||||||
labelFixedWidth?: number;
|
labelFixedWidth?: number;
|
||||||
useEditButton?: boolean;
|
buttonIcon?: IconComponent;
|
||||||
editModeContent?: React.ReactNode;
|
editModeContent?: React.ReactNode;
|
||||||
editModeContentOnly?: boolean;
|
editModeContentOnly?: boolean;
|
||||||
displayModeContent: React.ReactNode;
|
displayModeContent: React.ReactNode;
|
||||||
@ -90,7 +90,7 @@ export const InlineCellContainer = ({
|
|||||||
IconLabel,
|
IconLabel,
|
||||||
label,
|
label,
|
||||||
labelFixedWidth,
|
labelFixedWidth,
|
||||||
useEditButton,
|
buttonIcon,
|
||||||
editModeContent,
|
editModeContent,
|
||||||
displayModeContent,
|
displayModeContent,
|
||||||
customEditHotkeyScope,
|
customEditHotkeyScope,
|
||||||
@ -118,10 +118,7 @@ export const InlineCellContainer = ({
|
|||||||
};
|
};
|
||||||
|
|
||||||
const showEditButton =
|
const showEditButton =
|
||||||
!isInlineCellInEditMode &&
|
buttonIcon && !isInlineCellInEditMode && isHovered && !editModeContentOnly;
|
||||||
isHovered &&
|
|
||||||
useEditButton &&
|
|
||||||
!editModeContentOnly;
|
|
||||||
|
|
||||||
const theme = useTheme();
|
const theme = useTheme();
|
||||||
|
|
||||||
@ -171,7 +168,7 @@ export const InlineCellContainer = ({
|
|||||||
transition={{ duration: 0.1 }}
|
transition={{ duration: 0.1 }}
|
||||||
whileHover={{ scale: 1.04 }}
|
whileHover={{ scale: 1.04 }}
|
||||||
>
|
>
|
||||||
<InlineCellEditButton />
|
<InlineCellButton Icon={buttonIcon} />
|
||||||
</StyledEditButtonContainer>
|
</StyledEditButtonContainer>
|
||||||
)}
|
)}
|
||||||
</StyledClickableContainer>
|
</StyledClickableContainer>
|
||||||
|
|||||||
@ -1,9 +1,9 @@
|
|||||||
import { FloatingIconButton } from '@/ui/button/components/FloatingIconButton';
|
import { FloatingIconButton } from '@/ui/button/components/FloatingIconButton';
|
||||||
import { IconPencil } from '@/ui/icon';
|
import { IconComponent } from '@/ui/icon/types/IconComponent';
|
||||||
|
|
||||||
import { useInlineCell } from '../hooks/useInlineCell';
|
import { useInlineCell } from '../hooks/useInlineCell';
|
||||||
|
|
||||||
export const InlineCellEditButton = () => {
|
export const InlineCellButton = ({ Icon }: { Icon: IconComponent }) => {
|
||||||
const { openInlineCell } = useInlineCell();
|
const { openInlineCell } = useInlineCell();
|
||||||
|
|
||||||
const handleClick = () => {
|
const handleClick = () => {
|
||||||
@ -14,7 +14,7 @@ export const InlineCellEditButton = () => {
|
|||||||
<FloatingIconButton
|
<FloatingIconButton
|
||||||
size="small"
|
size="small"
|
||||||
onClick={handleClick}
|
onClick={handleClick}
|
||||||
Icon={IconPencil}
|
Icon={Icon}
|
||||||
data-testid="inline-cell-edit-mode-container"
|
data-testid="inline-cell-edit-mode-container"
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
|
|||||||
@ -68,7 +68,7 @@ export const TableCell = ({
|
|||||||
/>
|
/>
|
||||||
}
|
}
|
||||||
nonEditModeContent={<FieldDisplay />}
|
nonEditModeContent={<FieldDisplay />}
|
||||||
useEditButton={fieldDefinition.useEditButton}
|
buttonIcon={fieldDefinition.buttonIcon}
|
||||||
></TableCellContainer>
|
></TableCellContainer>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@ -0,0 +1,26 @@
|
|||||||
|
import styled from '@emotion/styled';
|
||||||
|
import { motion } from 'framer-motion';
|
||||||
|
|
||||||
|
import { FloatingIconButton } from '@/ui/button/components/FloatingIconButton';
|
||||||
|
import { IconComponent } from '@/ui/icon/types/IconComponent';
|
||||||
|
|
||||||
|
const StyledEditButtonContainer = styled(motion.div)`
|
||||||
|
position: absolute;
|
||||||
|
right: 5px;
|
||||||
|
`;
|
||||||
|
|
||||||
|
type TableCellButtonProps = {
|
||||||
|
onClick?: () => void;
|
||||||
|
Icon: IconComponent;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const TableCellButton = ({ onClick, Icon }: TableCellButtonProps) => (
|
||||||
|
<StyledEditButtonContainer
|
||||||
|
initial={{ opacity: 0 }}
|
||||||
|
animate={{ opacity: 1 }}
|
||||||
|
transition={{ duration: 0.1 }}
|
||||||
|
whileHover={{ scale: 1.04 }}
|
||||||
|
>
|
||||||
|
<FloatingIconButton size="small" onClick={onClick} Icon={Icon} />
|
||||||
|
</StyledEditButtonContainer>
|
||||||
|
);
|
||||||
@ -1,18 +1,21 @@
|
|||||||
import { ReactElement, useState } from 'react';
|
import { ReactElement, useContext, useState } from 'react';
|
||||||
import styled from '@emotion/styled';
|
import styled from '@emotion/styled';
|
||||||
|
|
||||||
|
import { useIsFieldEmpty } from '@/ui/field/hooks/useIsFieldEmpty';
|
||||||
import { useIsFieldInputOnly } from '@/ui/field/hooks/useIsFieldInputOnly';
|
import { useIsFieldInputOnly } from '@/ui/field/hooks/useIsFieldInputOnly';
|
||||||
|
import { IconComponent } from '@/ui/icon/types/IconComponent';
|
||||||
import { HotkeyScope } from '@/ui/utilities/hotkey/types/HotkeyScope';
|
import { HotkeyScope } from '@/ui/utilities/hotkey/types/HotkeyScope';
|
||||||
|
|
||||||
import { CellHotkeyScopeContext } from '../../contexts/CellHotkeyScopeContext';
|
import { CellHotkeyScopeContext } from '../../contexts/CellHotkeyScopeContext';
|
||||||
|
import { ColumnIndexContext } from '../../contexts/ColumnIndexContext';
|
||||||
import { TableHotkeyScope } from '../../types/TableHotkeyScope';
|
import { TableHotkeyScope } from '../../types/TableHotkeyScope';
|
||||||
import { useCurrentTableCellEditMode } from '../hooks/useCurrentTableCellEditMode';
|
import { useCurrentTableCellEditMode } from '../hooks/useCurrentTableCellEditMode';
|
||||||
import { useIsSoftFocusOnCurrentTableCell } from '../hooks/useIsSoftFocusOnCurrentTableCell';
|
import { useIsSoftFocusOnCurrentTableCell } from '../hooks/useIsSoftFocusOnCurrentTableCell';
|
||||||
import { useSetSoftFocusOnCurrentTableCell } from '../hooks/useSetSoftFocusOnCurrentTableCell';
|
import { useSetSoftFocusOnCurrentTableCell } from '../hooks/useSetSoftFocusOnCurrentTableCell';
|
||||||
import { useTableCell } from '../hooks/useTableCell';
|
import { useTableCell } from '../hooks/useTableCell';
|
||||||
|
|
||||||
|
import { TableCellButton } from './TableCellButton';
|
||||||
import { TableCellDisplayMode } from './TableCellDisplayMode';
|
import { TableCellDisplayMode } from './TableCellDisplayMode';
|
||||||
import { TableCellEditButton } from './TableCellEditButton';
|
|
||||||
import { TableCellEditMode } from './TableCellEditMode';
|
import { TableCellEditMode } from './TableCellEditMode';
|
||||||
import { TableCellSoftFocusMode } from './TableCellSoftFocusMode';
|
import { TableCellSoftFocusMode } from './TableCellSoftFocusMode';
|
||||||
|
|
||||||
@ -34,7 +37,7 @@ export type EditableCellProps = {
|
|||||||
editHotkeyScope?: HotkeyScope;
|
editHotkeyScope?: HotkeyScope;
|
||||||
transparent?: boolean;
|
transparent?: boolean;
|
||||||
maxContentWidth?: number;
|
maxContentWidth?: number;
|
||||||
useEditButton?: boolean;
|
buttonIcon?: IconComponent;
|
||||||
onSubmit?: () => void;
|
onSubmit?: () => void;
|
||||||
onCancel?: () => void;
|
onCancel?: () => void;
|
||||||
};
|
};
|
||||||
@ -51,16 +54,17 @@ export const TableCellContainer = ({
|
|||||||
editHotkeyScope,
|
editHotkeyScope,
|
||||||
transparent = false,
|
transparent = false,
|
||||||
maxContentWidth,
|
maxContentWidth,
|
||||||
useEditButton,
|
buttonIcon,
|
||||||
}: EditableCellProps) => {
|
}: EditableCellProps) => {
|
||||||
const { isCurrentTableCellInEditMode } = useCurrentTableCellEditMode();
|
const { isCurrentTableCellInEditMode } = useCurrentTableCellEditMode();
|
||||||
|
|
||||||
const [isHovered, setIsHovered] = useState(false);
|
const [isHovered, setIsHovered] = useState(false);
|
||||||
|
|
||||||
const setSoftFocusOnCurrentTableCell = useSetSoftFocusOnCurrentTableCell();
|
const setSoftFocusOnCurrentTableCell = useSetSoftFocusOnCurrentTableCell();
|
||||||
|
|
||||||
const { openTableCell } = useTableCell();
|
const { openTableCell } = useTableCell();
|
||||||
|
|
||||||
const handlePenClick = () => {
|
const handleButtonClick = () => {
|
||||||
setSoftFocusOnCurrentTableCell();
|
setSoftFocusOnCurrentTableCell();
|
||||||
openTableCell();
|
openTableCell();
|
||||||
};
|
};
|
||||||
@ -75,11 +79,16 @@ export const TableCellContainer = ({
|
|||||||
|
|
||||||
const editModeContentOnly = useIsFieldInputOnly();
|
const editModeContentOnly = useIsFieldInputOnly();
|
||||||
|
|
||||||
const showEditButton =
|
const isFirstColumnCell = useContext(ColumnIndexContext) === 0;
|
||||||
useEditButton &&
|
|
||||||
|
const isEmpty = useIsFieldEmpty();
|
||||||
|
|
||||||
|
const showButton =
|
||||||
|
buttonIcon &&
|
||||||
isHovered &&
|
isHovered &&
|
||||||
!isCurrentTableCellInEditMode &&
|
!isCurrentTableCellInEditMode &&
|
||||||
!editModeContentOnly;
|
!editModeContentOnly &&
|
||||||
|
(!isFirstColumnCell || !isEmpty);
|
||||||
|
|
||||||
const hasSoftFocus = useIsSoftFocusOnCurrentTableCell();
|
const hasSoftFocus = useIsSoftFocusOnCurrentTableCell();
|
||||||
|
|
||||||
@ -102,14 +111,18 @@ export const TableCellContainer = ({
|
|||||||
</TableCellEditMode>
|
</TableCellEditMode>
|
||||||
) : hasSoftFocus ? (
|
) : hasSoftFocus ? (
|
||||||
<>
|
<>
|
||||||
{showEditButton && <TableCellEditButton onClick={handlePenClick} />}
|
{showButton && (
|
||||||
|
<TableCellButton onClick={handleButtonClick} Icon={buttonIcon} />
|
||||||
|
)}
|
||||||
<TableCellSoftFocusMode>
|
<TableCellSoftFocusMode>
|
||||||
{editModeContentOnly ? editModeContent : nonEditModeContent}
|
{editModeContentOnly ? editModeContent : nonEditModeContent}
|
||||||
</TableCellSoftFocusMode>
|
</TableCellSoftFocusMode>
|
||||||
</>
|
</>
|
||||||
) : (
|
) : (
|
||||||
<>
|
<>
|
||||||
{showEditButton && <TableCellEditButton onClick={handlePenClick} />}
|
{showButton && (
|
||||||
|
<TableCellButton onClick={handleButtonClick} Icon={buttonIcon} />
|
||||||
|
)}
|
||||||
<TableCellDisplayMode isHovered={isHovered}>
|
<TableCellDisplayMode isHovered={isHovered}>
|
||||||
{editModeContentOnly ? editModeContent : nonEditModeContent}
|
{editModeContentOnly ? editModeContent : nonEditModeContent}
|
||||||
</TableCellDisplayMode>
|
</TableCellDisplayMode>
|
||||||
|
|||||||
@ -2,26 +2,25 @@ import styled from '@emotion/styled';
|
|||||||
import { motion } from 'framer-motion';
|
import { motion } from 'framer-motion';
|
||||||
|
|
||||||
import { FloatingIconButton } from '@/ui/button/components/FloatingIconButton';
|
import { FloatingIconButton } from '@/ui/button/components/FloatingIconButton';
|
||||||
import { IconPencil } from '@/ui/icon';
|
import { IconComponent } from '@/ui/icon/types/IconComponent';
|
||||||
|
|
||||||
const StyledEditButtonContainer = styled(motion.div)`
|
const StyledEditButtonContainer = styled(motion.div)`
|
||||||
position: absolute;
|
position: absolute;
|
||||||
right: 5px;
|
right: 5px;
|
||||||
`;
|
`;
|
||||||
|
|
||||||
type EditableCellEditButtonProps = {
|
type TableCellButtonProps = {
|
||||||
onClick?: () => void;
|
onClick?: () => void;
|
||||||
|
Icon: IconComponent;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const TableCellEditButton = ({
|
export const TableCellButton = ({ onClick, Icon }: TableCellButtonProps) => (
|
||||||
onClick,
|
|
||||||
}: EditableCellEditButtonProps) => (
|
|
||||||
<StyledEditButtonContainer
|
<StyledEditButtonContainer
|
||||||
initial={{ opacity: 0 }}
|
initial={{ opacity: 0 }}
|
||||||
animate={{ opacity: 1 }}
|
animate={{ opacity: 1 }}
|
||||||
transition={{ duration: 0.1 }}
|
transition={{ duration: 0.1 }}
|
||||||
whileHover={{ scale: 1.04 }}
|
whileHover={{ scale: 1.04 }}
|
||||||
>
|
>
|
||||||
<FloatingIconButton size="small" onClick={onClick} Icon={IconPencil} />
|
<FloatingIconButton size="small" onClick={onClick} Icon={Icon} />
|
||||||
</StyledEditButtonContainer>
|
</StyledEditButtonContainer>
|
||||||
);
|
);
|
||||||
|
|||||||
@ -1,10 +1,14 @@
|
|||||||
import { useContext } from 'react';
|
import { useContext } from 'react';
|
||||||
|
import { useNavigate } from 'react-router-dom';
|
||||||
|
|
||||||
|
import { FieldContext } from '@/ui/field/contexts/FieldContext';
|
||||||
|
import { useIsFieldEmpty } from '@/ui/field/hooks/useIsFieldEmpty';
|
||||||
import { useDragSelect } from '@/ui/utilities/drag-select/hooks/useDragSelect';
|
import { useDragSelect } from '@/ui/utilities/drag-select/hooks/useDragSelect';
|
||||||
import { useSetHotkeyScope } from '@/ui/utilities/hotkey/hooks/useSetHotkeyScope';
|
import { useSetHotkeyScope } from '@/ui/utilities/hotkey/hooks/useSetHotkeyScope';
|
||||||
import { HotkeyScope } from '@/ui/utilities/hotkey/types/HotkeyScope';
|
import { HotkeyScope } from '@/ui/utilities/hotkey/types/HotkeyScope';
|
||||||
|
|
||||||
import { CellHotkeyScopeContext } from '../../contexts/CellHotkeyScopeContext';
|
import { CellHotkeyScopeContext } from '../../contexts/CellHotkeyScopeContext';
|
||||||
|
import { ColumnIndexContext } from '../../contexts/ColumnIndexContext';
|
||||||
import { useCloseCurrentTableCellInEditMode } from '../../hooks/useCloseCurrentTableCellInEditMode';
|
import { useCloseCurrentTableCellInEditMode } from '../../hooks/useCloseCurrentTableCellInEditMode';
|
||||||
import { TableHotkeyScope } from '../../types/TableHotkeyScope';
|
import { TableHotkeyScope } from '../../types/TableHotkeyScope';
|
||||||
|
|
||||||
@ -30,7 +34,20 @@ export const useTableCell = () => {
|
|||||||
setHotkeyScope(TableHotkeyScope.TableSoftFocus);
|
setHotkeyScope(TableHotkeyScope.TableSoftFocus);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const navigate = useNavigate();
|
||||||
|
|
||||||
|
const isFirstColumnCell = useContext(ColumnIndexContext) === 0;
|
||||||
|
|
||||||
|
const isEmpty = useIsFieldEmpty();
|
||||||
|
|
||||||
|
const { entityId, fieldDefinition } = useContext(FieldContext);
|
||||||
|
|
||||||
const openTableCell = () => {
|
const openTableCell = () => {
|
||||||
|
if (isFirstColumnCell && !isEmpty && fieldDefinition.basePathToShowPage) {
|
||||||
|
navigate(`${fieldDefinition.basePathToShowPage}${entityId}`);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
setDragSelectionStartEnabled(false);
|
setDragSelectionStartEnabled(false);
|
||||||
setCurrentTableCellInEditMode();
|
setCurrentTableCellInEditMode();
|
||||||
|
|
||||||
|
|||||||
@ -13,6 +13,7 @@ import {
|
|||||||
IconCalendar,
|
IconCalendar,
|
||||||
IconLink,
|
IconLink,
|
||||||
IconMap,
|
IconMap,
|
||||||
|
IconPencil,
|
||||||
IconTarget,
|
IconTarget,
|
||||||
IconUserCircle,
|
IconUserCircle,
|
||||||
IconUsers,
|
IconUsers,
|
||||||
@ -29,7 +30,7 @@ export const companyShowFieldDefinition: FieldDefinition<FieldMetadata>[] = [
|
|||||||
fieldName: 'domainName',
|
fieldName: 'domainName',
|
||||||
placeHolder: 'URL',
|
placeHolder: 'URL',
|
||||||
},
|
},
|
||||||
useEditButton: true,
|
buttonIcon: IconPencil,
|
||||||
} satisfies FieldDefinition<FieldURLMetadata>,
|
} satisfies FieldDefinition<FieldURLMetadata>,
|
||||||
{
|
{
|
||||||
key: 'accountOwner',
|
key: 'accountOwner',
|
||||||
@ -79,7 +80,7 @@ export const companyShowFieldDefinition: FieldDefinition<FieldMetadata>[] = [
|
|||||||
fieldName: 'xUrl',
|
fieldName: 'xUrl',
|
||||||
placeHolder: 'X',
|
placeHolder: 'X',
|
||||||
},
|
},
|
||||||
useEditButton: true,
|
buttonIcon: IconPencil,
|
||||||
} satisfies FieldDefinition<FieldURLMetadata>,
|
} satisfies FieldDefinition<FieldURLMetadata>,
|
||||||
{
|
{
|
||||||
key: 'createdAt',
|
key: 'createdAt',
|
||||||
|
|||||||
@ -15,6 +15,7 @@ import {
|
|||||||
IconCalendar,
|
IconCalendar,
|
||||||
IconMail,
|
IconMail,
|
||||||
IconMap,
|
IconMap,
|
||||||
|
IconPencil,
|
||||||
IconPhone,
|
IconPhone,
|
||||||
} from '@/ui/icon';
|
} from '@/ui/icon';
|
||||||
import { Entity } from '@/ui/input/relation-picker/types/EntityTypeForSelect';
|
import { Entity } from '@/ui/input/relation-picker/types/EntityTypeForSelect';
|
||||||
@ -35,7 +36,7 @@ export const personShowFieldDefinition: FieldDefinition<FieldMetadata>[] = [
|
|||||||
name: 'Company',
|
name: 'Company',
|
||||||
Icon: IconBuildingSkyscraper,
|
Icon: IconBuildingSkyscraper,
|
||||||
type: 'relation',
|
type: 'relation',
|
||||||
useEditButton: true,
|
buttonIcon: IconPencil,
|
||||||
metadata: {
|
metadata: {
|
||||||
fieldName: 'company',
|
fieldName: 'company',
|
||||||
relationType: Entity.Company,
|
relationType: Entity.Company,
|
||||||
@ -50,7 +51,7 @@ export const personShowFieldDefinition: FieldDefinition<FieldMetadata>[] = [
|
|||||||
fieldName: 'phone',
|
fieldName: 'phone',
|
||||||
placeHolder: 'Phone',
|
placeHolder: 'Phone',
|
||||||
},
|
},
|
||||||
useEditButton: true,
|
buttonIcon: IconPencil,
|
||||||
} satisfies FieldDefinition<FieldPhoneMetadata>,
|
} satisfies FieldDefinition<FieldPhoneMetadata>,
|
||||||
{
|
{
|
||||||
key: 'jobTitle',
|
key: 'jobTitle',
|
||||||
@ -81,7 +82,7 @@ export const personShowFieldDefinition: FieldDefinition<FieldMetadata>[] = [
|
|||||||
fieldName: 'linkedinUrl',
|
fieldName: 'linkedinUrl',
|
||||||
placeHolder: 'Linkedin URL',
|
placeHolder: 'Linkedin URL',
|
||||||
},
|
},
|
||||||
useEditButton: true,
|
buttonIcon: IconPencil,
|
||||||
} satisfies FieldDefinition<FieldURLMetadata>,
|
} satisfies FieldDefinition<FieldURLMetadata>,
|
||||||
{
|
{
|
||||||
key: 'xUrl',
|
key: 'xUrl',
|
||||||
@ -92,7 +93,7 @@ export const personShowFieldDefinition: FieldDefinition<FieldMetadata>[] = [
|
|||||||
fieldName: 'xUrl',
|
fieldName: 'xUrl',
|
||||||
placeHolder: 'X URL',
|
placeHolder: 'X URL',
|
||||||
},
|
},
|
||||||
useEditButton: true,
|
buttonIcon: IconPencil,
|
||||||
} satisfies FieldDefinition<FieldURLMetadata>,
|
} satisfies FieldDefinition<FieldURLMetadata>,
|
||||||
{
|
{
|
||||||
key: 'createdAt',
|
key: 'createdAt',
|
||||||
|
|||||||
Reference in New Issue
Block a user