fix: content getting hide on drag and drop in stage view cards (#7621)

## ISSUE

-  Closes #7388 

## Demo



https://github.com/user-attachments/assets/193813aa-def9-406b-9fe7-397627bb1242

- [ ] Table Row Drag WIP

---------

Co-authored-by: Lucas Bordeau <bordeau.lucas@gmail.com>
This commit is contained in:
Nabhag Motivaras
2024-11-05 20:33:24 +05:30
committed by GitHub
parent 84b0b78b6f
commit 3793f6c451
9 changed files with 184 additions and 145 deletions

View File

@@ -23,14 +23,13 @@ import { RecordBoardScrollWrapperContext } from '@/ui/utilities/scroll/contexts/
import { extractComponentState } from '@/ui/utilities/state/component-state/utils/extractComponentState';
import styled from '@emotion/styled';
import { ReactNode, useContext, useState } from 'react';
import { useInView } from 'react-intersection-observer';
import { InView, useInView } from 'react-intersection-observer';
import { useRecoilState, useRecoilValue, useSetRecoilState } from 'recoil';
import {
AnimatedEaseInOut,
AvatarChipVariant,
Checkbox,
CheckboxVariant,
ChipSize,
IconEye,
IconEyeOff,
LightIconButton,
@@ -147,10 +146,6 @@ const StyledCompactIconContainer = styled.div`
margin-left: ${({ theme }) => theme.spacing(1)};
`;
const StyledRecordInlineCellPlaceholder = styled.div`
height: 24px;
`;
export const RecordBoardCard = ({
isCreating = false,
onCreateSuccess,
@@ -240,7 +235,7 @@ export const RecordBoardCard = ({
const scrollWrapperRef = useContext(RecordBoardScrollWrapperContext);
const { ref: cardRef, inView } = useInView({
const { ref: cardRef } = useInView({
root: scrollWrapperRef?.ref.current,
rootMargin: '1000px',
});
@@ -256,126 +251,123 @@ export const RecordBoardCard = ({
return (
<StyledBoardCardWrapper onContextMenu={handleActionMenuDropdown}>
{!isCreating && <RecordValueSetterEffect recordId={recordId} />}
<StyledBoardCard
ref={cardRef}
selected={isCurrentCardSelected}
onMouseLeave={onMouseLeaveBoard}
onClick={() => {
if (!isCreating) {
setIsCurrentCardSelected(!isCurrentCardSelected);
}
}}
>
<StyledBoardCardHeader showCompactView={isCompactModeActive}>
{isCreating && position !== undefined ? (
<RecordInlineCellEditMode>
<StyledTextInput
autoFocus
value={newLabelValue}
onInputEnter={() =>
handleInputEnter(
labelIdentifierField?.label ?? '',
newLabelValue,
position,
onCreateSuccess,
)
}
onBlur={() =>
handleBlur(
labelIdentifierField?.label ?? '',
newLabelValue,
position,
onCreateSuccess,
)
}
onChange={(text: string) => setNewLabelValue(text)}
placeholder={labelIdentifierField?.label}
/>
</RecordInlineCellEditMode>
) : (
<RecordIdentifierChip
objectNameSingular={objectMetadataItem.nameSingular}
record={record as ObjectRecord}
variant={AvatarChipVariant.Transparent}
size={ChipSize.Large}
/>
)}
{!isCreating && (
<>
{isCompactModeActive && (
<StyledCompactIconContainer className="compact-icon-container">
<LightIconButton
Icon={isCardExpanded ? IconEyeOff : IconEye}
accent="tertiary"
onClick={(e) => {
e.stopPropagation();
setIsCardExpanded((prev) => !prev);
}}
/>
</StyledCompactIconContainer>
)}
<StyledCheckboxContainer className="checkbox-container">
<Checkbox
hoverable
checked={isCurrentCardSelected}
onChange={() =>
setIsCurrentCardSelected(!isCurrentCardSelected)
}
variant={CheckboxVariant.Secondary}
/>
</StyledCheckboxContainer>
</>
)}
</StyledBoardCardHeader>
<AnimatedEaseInOut
isOpen={isCardExpanded || !isCompactModeActive}
initial={false}
<InView>
<StyledBoardCard
ref={cardRef}
selected={isCurrentCardSelected}
onMouseLeave={onMouseLeaveBoard}
onClick={() => {
if (!isCreating) {
setIsCurrentCardSelected(!isCurrentCardSelected);
}
}}
>
<StyledBoardCardBody>
{visibleFieldDefinitionsFiltered.map((fieldDefinition) => (
<PreventSelectOnClickContainer
key={fieldDefinition.fieldMetadataId}
>
<FieldContext.Provider
value={{
recordId: isCreating ? '' : recordId,
maxWidth: 156,
recoilScopeId:
(isCreating ? 'new' : recordId) +
fieldDefinition.fieldMetadataId,
isLabelIdentifier: false,
fieldDefinition: {
disableTooltip: false,
fieldMetadataId: fieldDefinition.fieldMetadataId,
label: fieldDefinition.label,
iconName: fieldDefinition.iconName,
type: fieldDefinition.type,
metadata: fieldDefinition.metadata,
defaultValue: fieldDefinition.defaultValue,
editButtonIcon: getFieldButtonIcon({
metadata: fieldDefinition.metadata,
type: fieldDefinition.type,
}),
settings: fieldDefinition.settings,
},
useUpdateRecord: useUpdateOneRecordHook,
hotkeyScope: InlineCellHotkeyScope.InlineCell,
}}
<StyledBoardCardHeader showCompactView={isCompactModeActive}>
{isCreating && position !== undefined ? (
<RecordInlineCellEditMode>
<StyledTextInput
autoFocus
value={newLabelValue}
onInputEnter={() =>
handleInputEnter(
labelIdentifierField?.label ?? '',
newLabelValue,
position,
onCreateSuccess,
)
}
onBlur={() =>
handleBlur(
labelIdentifierField?.label ?? '',
newLabelValue,
position,
onCreateSuccess,
)
}
onChange={(text: string) => setNewLabelValue(text)}
placeholder={labelIdentifierField?.label}
/>
</RecordInlineCellEditMode>
) : (
<RecordIdentifierChip
objectNameSingular={objectMetadataItem.nameSingular}
record={record as ObjectRecord}
variant={AvatarChipVariant.Transparent}
/>
)}
{!isCreating && (
<>
{isCompactModeActive && (
<StyledCompactIconContainer className="compact-icon-container">
<LightIconButton
Icon={isCardExpanded ? IconEyeOff : IconEye}
accent="tertiary"
onClick={(e) => {
e.stopPropagation();
setIsCardExpanded((prev) => !prev);
}}
/>
</StyledCompactIconContainer>
)}
<StyledCheckboxContainer className="checkbox-container">
<Checkbox
hoverable
checked={isCurrentCardSelected}
onChange={() =>
setIsCurrentCardSelected(!isCurrentCardSelected)
}
variant={CheckboxVariant.Secondary}
/>
</StyledCheckboxContainer>
</>
)}
</StyledBoardCardHeader>
<AnimatedEaseInOut
isOpen={isCardExpanded || !isCompactModeActive}
initial={false}
>
<StyledBoardCardBody>
{visibleFieldDefinitionsFiltered.map((fieldDefinition) => (
<PreventSelectOnClickContainer
key={fieldDefinition.fieldMetadataId}
>
{inView ? (
<FieldContext.Provider
value={{
recordId: isCreating ? '' : recordId,
maxWidth: 156,
recoilScopeId:
(isCreating ? 'new' : recordId) +
fieldDefinition.fieldMetadataId,
isLabelIdentifier: false,
fieldDefinition: {
disableTooltip: false,
fieldMetadataId: fieldDefinition.fieldMetadataId,
label: fieldDefinition.label,
iconName: fieldDefinition.iconName,
type: fieldDefinition.type,
metadata: fieldDefinition.metadata,
defaultValue: fieldDefinition.defaultValue,
editButtonIcon: getFieldButtonIcon({
metadata: fieldDefinition.metadata,
type: fieldDefinition.type,
}),
settings: fieldDefinition.settings,
},
useUpdateRecord: useUpdateOneRecordHook,
hotkeyScope: InlineCellHotkeyScope.InlineCell,
}}
>
<RecordInlineCell />
) : (
<StyledRecordInlineCellPlaceholder />
)}
</FieldContext.Provider>
</PreventSelectOnClickContainer>
))}
</StyledBoardCardBody>
</AnimatedEaseInOut>
</StyledBoardCard>
</FieldContext.Provider>
</PreventSelectOnClickContainer>
))}
</StyledBoardCardBody>
</AnimatedEaseInOut>
</StyledBoardCard>
</InView>
</StyledBoardCardWrapper>
);
};

View File

@@ -1,5 +1,5 @@
import { createContext } from 'react';
import { DraggableProvidedDragHandleProps } from '@hello-pangea/dnd';
import { createContext } from 'react';
export type RecordTableRowContextProps = {
pathToShowPage: string;

View File

@@ -9,11 +9,10 @@ import { Checkbox } from 'twenty-ui';
const StyledContainer = styled.div`
align-items: center;
cursor: pointer;
display: flex;
height: 32px;
justify-content: center;
min-width: 24px;
`;
export const RecordTableCellCheckbox = () => {

View File

@@ -16,6 +16,7 @@ const StyledTd = styled.td<{
left?: number;
hasRightBorder?: boolean;
hasBottomBorder?: boolean;
width?: number;
}>`
border-bottom: 1px solid
${({ borderColor, hasBottomBorder }) =>
@@ -32,13 +33,12 @@ const StyledTd = styled.td<{
background: ${({ backgroundColor }) => backgroundColor};
z-index: ${({ zIndex }) => (isDefined(zIndex) ? zIndex : 'auto')};
${({ isDragging }) =>
isDragging
? `
background-color: transparent;
border-color: transparent;
`
`
: ''}
${({ freezeFirstColumns }) =>
@@ -60,6 +60,7 @@ export const RecordTableTd = ({
left,
hasRightBorder = true,
hasBottomBorder = true,
width,
...dragHandleProps
}: {
className?: string;
@@ -72,6 +73,7 @@ export const RecordTableTd = ({
hasRightBorder?: boolean;
hasBottomBorder?: boolean;
left?: number;
width?: number;
} & (Partial<DraggableProvidedDragHandleProps> | null)) => {
const { theme } = useContext(ThemeContext);
@@ -94,6 +96,7 @@ export const RecordTableTd = ({
left={left}
hasRightBorder={hasRightBorder}
hasBottomBorder={hasBottomBorder}
width={width}
// eslint-disable-next-line react/jsx-props-no-spreading
{...dragHandleProps}
>

View File

@@ -175,6 +175,7 @@ export const RecordTableHeaderCell = ({
resizedFieldKey,
resizeFieldOffsetState,
tableColumnsByKey,
setResizedFieldKey,
tableColumns,
handleColumnsChange,
],

View File

@@ -1,9 +1,8 @@
import { useContext } from 'react';
import { RecordTableRowContext } from '@/object-record/record-table/contexts/RecordTableRowContext';
import { RecordTableTd } from '@/object-record/record-table/record-table-cell/components/RecordTableTd';
import { visibleTableColumnsComponentSelector } from '@/object-record/record-table/states/selectors/visibleTableColumnsComponentSelector';
import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2';
import { useContext } from 'react';
export const RecordTableCellsEmpty = () => {
const { isSelected } = useContext(RecordTableRowContext);

View File

@@ -5,10 +5,16 @@ import { RecordTableCell } from '@/object-record/record-table/record-table-cell/
import { RecordTableCellWrapper } from '@/object-record/record-table/record-table-cell/components/RecordTableCellWrapper';
import { RecordTableTd } from '@/object-record/record-table/record-table-cell/components/RecordTableTd';
import { visibleTableColumnsComponentSelector } from '@/object-record/record-table/states/selectors/visibleTableColumnsComponentSelector';
import { tableCellWidthsComponentState } from '@/object-record/record-table/states/tableCellWidthsComponentState';
import { useRecoilComponentStateV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentStateV2';
import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2';
export const RecordTableCellsVisible = () => {
const { isDragging, isSelected } = useContext(RecordTableRowContext);
const { isSelected, isDragging } = useContext(RecordTableRowContext);
const [tableCellWidths] = useRecoilComponentStateV2(
tableCellWidthsComponentState,
);
const visibleTableColumns = useRecoilComponentValueV2(
visibleTableColumnsComponentSelector,
@@ -19,22 +25,29 @@ export const RecordTableCellsVisible = () => {
return (
<>
<RecordTableCellWrapper column={visibleTableColumns[0]} columnIndex={0}>
<RecordTableTd isSelected={isSelected}>
<RecordTableTd
isSelected={isSelected}
isDragging={isDragging}
width={tableCellWidths[2]}
>
<RecordTableCell />
</RecordTableTd>
</RecordTableCellWrapper>
{!isDragging &&
tableColumnsAfterFirst.map((column, columnIndex) => (
<RecordTableCellWrapper
key={column.fieldMetadataId}
column={column}
columnIndex={columnIndex + 1}
{tableColumnsAfterFirst.map((column, columnIndex) => (
<RecordTableCellWrapper
key={column.fieldMetadataId}
column={column}
columnIndex={columnIndex + 1}
>
<RecordTableTd
isSelected={isSelected}
isDragging={isDragging}
width={tableCellWidths[columnIndex + 3] - 1}
>
<RecordTableTd isSelected={isSelected}>
<RecordTableCell />
</RecordTableTd>
</RecordTableCellWrapper>
))}
<RecordTableCell />
</RecordTableTd>
</RecordTableCellWrapper>
))}
</>
);
};

View File

@@ -1,6 +1,6 @@
import { useTheme } from '@emotion/react';
import { Draggable } from '@hello-pangea/dnd';
import { ReactNode, useContext, useEffect } from 'react';
import { ReactNode, useContext, useEffect, useRef } from 'react';
import { useInView } from 'react-intersection-observer';
import { getBasePathToShowPage } from '@/object-metadata/utils/getBasePathToShowPage';
@@ -9,8 +9,10 @@ import { RecordTableContext } from '@/object-record/record-table/contexts/Record
import { RecordTableRowContext } from '@/object-record/record-table/contexts/RecordTableRowContext';
import { RecordTableTr } from '@/object-record/record-table/record-table-row/components/RecordTableTr';
import { isRowSelectedComponentFamilyState } from '@/object-record/record-table/record-table-row/states/isRowSelectedComponentFamilyState';
import { tableCellWidthsComponentState } from '@/object-record/record-table/states/tableCellWidthsComponentState';
import { RecordTableWithWrappersScrollWrapperContext } from '@/ui/utilities/scroll/contexts/ScrollWrapperContexts';
import { useRecoilComponentFamilyValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentFamilyValueV2';
import { useRecoilComponentStateV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentStateV2';
export const RecordTableRowWrapper = ({
recordId,
@@ -23,6 +25,8 @@ export const RecordTableRowWrapper = ({
isPendingRow?: boolean;
children: ReactNode;
}) => {
const trRef = useRef<HTMLTableRowElement>(null);
const { objectMetadataItem } = useContext(RecordTableContext);
const { onIndexRecordsLoaded } = useContext(RecordIndexRootPropsContext);
@@ -44,6 +48,24 @@ export const RecordTableRowWrapper = ({
rootMargin: '1000px',
});
const [, setTableCellWidths] = useRecoilComponentStateV2(
tableCellWidthsComponentState,
);
useEffect(() => {
if (rowIndex === 0) {
const tdArray = Array.from(
trRef.current?.getElementsByTagName('td') ?? [],
);
const tdWidths = tdArray.map((td) => {
return td.getBoundingClientRect().width;
});
setTableCellWidths(tdWidths);
}
}, [trRef, rowIndex, setTableCellWidths]);
// TODO: find a better way to emit this event
useEffect(() => {
if (inView) {
@@ -56,6 +78,8 @@ export const RecordTableRowWrapper = ({
{(draggableProvided, draggableSnapshot) => (
<RecordTableTr
ref={(node) => {
// @ts-expect-error - TS doesn't know that node.current is assignable
trRef.current = node;
elementRef(node);
draggableProvided.innerRef(node);
}}

View File

@@ -0,0 +1,8 @@
import { RecordTableComponentInstanceContext } from '@/object-record/record-table/states/context/RecordTableComponentInstanceContext';
import { createComponentStateV2 } from '@/ui/utilities/state/component-state/utils/createComponentStateV2';
export const tableCellWidthsComponentState = createComponentStateV2<number[]>({
key: 'tableCellWidthsComponentState',
defaultValue: [],
componentInstanceContext: RecordTableComponentInstanceContext,
});