Table refactor : removed z-index dynamic logic completely and flex-wrap (#18466)
This PR removes the leftovers from the z-index dynamic logic removal. It also removes the flex-wrap mechanism that was used to have all the cells in the same div, and instead creates a container for each part of the table : header, body and footer, so that z-index management becomes straighforward. We also fix some minor bugs. ## Demo https://github.com/user-attachments/assets/29dc4966-376d-4eb1-9e37-99769e77f4f4 https://github.com/user-attachments/assets/78218517-812a-4531-84c3-067700b46b59
This commit is contained in:
+3
-4
@@ -15,12 +15,12 @@ import { recordTableHoverPositionComponentState } from '@/object-record/record-t
|
||||
import { isSomeCellInEditModeComponentSelector } from '@/object-record/record-table/states/selectors/isSomeCellInEditModeComponentSelector';
|
||||
import { DragSelect } from '@/ui/utilities/drag-select/components/DragSelect';
|
||||
import { RECORD_INDEX_DRAG_SELECT_BOUNDARY_CLASS } from '@/ui/utilities/drag-select/constants/RecordIndecDragSelectBoundaryClass';
|
||||
import { useAtomComponentStateCallbackState } from '@/ui/utilities/state/jotai/hooks/useAtomComponentStateCallbackState';
|
||||
import { useAtomComponentSelectorCallbackState } from '@/ui/utilities/state/jotai/hooks/useAtomComponentSelectorCallbackState';
|
||||
import { useAtomComponentFamilyStateCallbackState } from '@/ui/utilities/state/jotai/hooks/useAtomComponentFamilyStateCallbackState';
|
||||
import { useAtomComponentSelectorCallbackState } from '@/ui/utilities/state/jotai/hooks/useAtomComponentSelectorCallbackState';
|
||||
import { useAtomComponentStateCallbackState } from '@/ui/utilities/state/jotai/hooks/useAtomComponentStateCallbackState';
|
||||
import { styled } from '@linaria/react';
|
||||
import { useCallback, useMemo, useRef, useState } from 'react';
|
||||
import { useStore } from 'jotai';
|
||||
import { useCallback, useMemo, useRef, useState } from 'react';
|
||||
|
||||
const StyledTableContainer = styled.div`
|
||||
display: flex;
|
||||
@@ -142,7 +142,6 @@ export const RecordTableContent = ({
|
||||
id={RECORD_TABLE_HTML_ID}
|
||||
onMouseMove={handleDelegatedMouseMove}
|
||||
onMouseLeave={handleMouseLeave}
|
||||
hasRecordGroups={hasRecordGroups}
|
||||
>
|
||||
<RecordTableHeader />
|
||||
{hasRecordGroups ? (
|
||||
|
||||
-7
@@ -1,4 +1,3 @@
|
||||
import { hasRecordGroupsComponentSelector } from '@/object-record/record-group/states/selectors/hasRecordGroupsComponentSelector';
|
||||
import { RecordTableColumnWidthEffect } from '@/object-record/record-table/components/RecordTableColumnWidthEffect';
|
||||
import {
|
||||
getRecordTableColumnWidthInlineStyles,
|
||||
@@ -18,7 +17,6 @@ import { resizeFieldOffsetComponentState } from '@/object-record/record-table/st
|
||||
import { shouldCompactRecordTableFirstColumnComponentState } from '@/object-record/record-table/states/shouldCompactRecordTableFirstColumnComponentState';
|
||||
import { computeVisibleRecordFieldsWidthOnTable } from '@/object-record/record-table/utils/computeVisibleRecordFieldsWidthOnTable';
|
||||
import { RecordTableVirtualizedDataChangedEffect } from '@/object-record/record-table/virtualization/components/RecordTableVirtualizedDataChangedEffect';
|
||||
import { useAtomComponentSelectorValue } from '@/ui/utilities/state/jotai/hooks/useAtomComponentSelectorValue';
|
||||
import { useAtomComponentStateValue } from '@/ui/utilities/state/jotai/hooks/useAtomComponentStateValue';
|
||||
import { styled } from '@linaria/react';
|
||||
import { useMemo } from 'react';
|
||||
@@ -81,10 +79,6 @@ export const RecordTableEmpty = ({ tableBodyRef }: RecordTableEmptyProps) => {
|
||||
emptyTableContainerComputedWidth,
|
||||
);
|
||||
|
||||
const hasRecordGroups = useAtomComponentSelectorValue(
|
||||
hasRecordGroupsComponentSelector,
|
||||
);
|
||||
|
||||
const columnWidthStyles = useMemo(
|
||||
() => getRecordTableColumnWidthInlineStyles(visibleRecordFields),
|
||||
[visibleRecordFields],
|
||||
@@ -96,7 +90,6 @@ export const RecordTableEmpty = ({ tableBodyRef }: RecordTableEmptyProps) => {
|
||||
ref={tableBodyRef}
|
||||
style={columnWidthStyles}
|
||||
id={RECORD_TABLE_HTML_ID}
|
||||
hasRecordGroups={hasRecordGroups}
|
||||
>
|
||||
<RecordTableHeader />
|
||||
</RecordTableStyleWrapper>
|
||||
|
||||
+9
-2
@@ -5,8 +5,15 @@ import { RecordTableVirtualizedDebugHelper } from '@/object-record/record-table/
|
||||
import { NUMBER_OF_VIRTUALIZED_ROWS } from '@/object-record/record-table/virtualization/constants/NumberOfVirtualizedRows';
|
||||
import { totalNumberOfRecordsToVirtualizeComponentState } from '@/object-record/record-table/virtualization/states/totalNumberOfRecordsToVirtualizeComponentState';
|
||||
import { useAtomComponentStateValue } from '@/ui/utilities/state/jotai/hooks/useAtomComponentStateValue';
|
||||
import { styled } from '@linaria/react';
|
||||
import { getContiguousIncrementalValues } from 'twenty-shared/utils';
|
||||
|
||||
const StyledNoRecordGroupContainer = styled.div`
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
width: 100%;
|
||||
`;
|
||||
|
||||
export const RecordTableNoRecordGroupRows = () => {
|
||||
const totalNumberOfRecordsToVirtualize =
|
||||
useAtomComponentStateValue(
|
||||
@@ -21,7 +28,7 @@ export const RecordTableNoRecordGroupRows = () => {
|
||||
const virtualRowIndices = getContiguousIncrementalValues(numberOfRows);
|
||||
|
||||
return (
|
||||
<>
|
||||
<StyledNoRecordGroupContainer>
|
||||
<RecordTableVirtualizedBodyPlaceholder />
|
||||
{virtualRowIndices.map((virtualRowIndex) => {
|
||||
return (
|
||||
@@ -33,6 +40,6 @@ export const RecordTableNoRecordGroupRows = () => {
|
||||
})}
|
||||
<RecordTableNoRecordGroupAddNew />
|
||||
<RecordTableVirtualizedDebugHelper />
|
||||
</>
|
||||
</StyledNoRecordGroupContainer>
|
||||
);
|
||||
};
|
||||
|
||||
-1
@@ -60,7 +60,6 @@ export const RecordTableRecordGroupRows = () => {
|
||||
recordId={recordId}
|
||||
rowIndexForFocus={rowIndex}
|
||||
rowIndexForDrag={rowIndexInGroup}
|
||||
isFirstRowOfGroup={rowIndexInGroup === 0}
|
||||
/>
|
||||
);
|
||||
})}
|
||||
|
||||
+15
-37
@@ -35,16 +35,17 @@ export const getRecordTableColumnWidthInlineStyles = (
|
||||
visibleRecordFields: RecordField[],
|
||||
): Record<string, string> => {
|
||||
const style: Record<string, string> = {};
|
||||
|
||||
for (let i = 0; i < visibleRecordFields.length; i++) {
|
||||
style[`--record-table-column-field-${i}`] =
|
||||
`${visibleRecordFields[i].size}px`;
|
||||
}
|
||||
|
||||
return style;
|
||||
};
|
||||
|
||||
const StyledTable = styled.div<{
|
||||
isDragging?: boolean;
|
||||
hasRecordGroups: boolean;
|
||||
}>`
|
||||
& > * {
|
||||
pointer-events: ${({ isDragging }) =>
|
||||
@@ -52,23 +53,13 @@ const StyledTable = styled.div<{
|
||||
}
|
||||
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
flex-direction: column;
|
||||
position: relative;
|
||||
|
||||
width: 100%;
|
||||
|
||||
div.header-cell {
|
||||
position: sticky;
|
||||
top: 0;
|
||||
|
||||
${VerticalScrollBoxShadowCSS}
|
||||
}
|
||||
|
||||
div.header-cell:nth-of-type(n + 5) {
|
||||
z-index: ${({ hasRecordGroups }) =>
|
||||
hasRecordGroups
|
||||
? TABLE_Z_INDEX.headerColumns.withGroups.headerColumnsNormal
|
||||
: TABLE_Z_INDEX.headerColumns.withoutGroups.headerColumnsNormal};
|
||||
z-index: ${TABLE_Z_INDEX.headerColumns.headerColumnsNormal};
|
||||
}
|
||||
|
||||
div.header-cell:nth-of-type(1) {
|
||||
@@ -76,34 +67,30 @@ const StyledTable = styled.div<{
|
||||
|
||||
left: 0px;
|
||||
|
||||
z-index: ${({ hasRecordGroups }) =>
|
||||
hasRecordGroups
|
||||
? TABLE_Z_INDEX.headerColumns.withGroups.headerColumnsSticky
|
||||
: TABLE_Z_INDEX.headerColumns.withoutGroups.headerColumnsSticky};
|
||||
position: sticky;
|
||||
|
||||
z-index: ${TABLE_Z_INDEX.headerColumns.headerColumnsSticky};
|
||||
}
|
||||
|
||||
div.header-cell:nth-of-type(2) {
|
||||
background-color: ${themeCssVariables.background.primary};
|
||||
|
||||
left: ${RECORD_TABLE_COLUMN_DRAG_AND_DROP_WIDTH}px;
|
||||
position: sticky;
|
||||
|
||||
top: 0;
|
||||
|
||||
z-index: ${({ hasRecordGroups }) =>
|
||||
hasRecordGroups
|
||||
? TABLE_Z_INDEX.headerColumns.withGroups.headerColumnsSticky
|
||||
: TABLE_Z_INDEX.headerColumns.withoutGroups.headerColumnsSticky};
|
||||
z-index: ${TABLE_Z_INDEX.headerColumns.headerColumnsSticky};
|
||||
}
|
||||
|
||||
div.header-cell:nth-of-type(3) {
|
||||
background-color: ${themeCssVariables.background.primary};
|
||||
left: ${`${RECORD_TABLE_COLUMN_DRAG_AND_DROP_WIDTH + RECORD_TABLE_COLUMN_CHECKBOX_WIDTH}px`};
|
||||
position: sticky;
|
||||
|
||||
right: 0;
|
||||
|
||||
z-index: ${({ hasRecordGroups }) =>
|
||||
hasRecordGroups
|
||||
? TABLE_Z_INDEX.headerColumns.withGroups.headerColumnsSticky
|
||||
: TABLE_Z_INDEX.headerColumns.withoutGroups.headerColumnsSticky};
|
||||
z-index: ${TABLE_Z_INDEX.headerColumns.headerColumnsSticky};
|
||||
|
||||
${HorizontalScrollBoxShadowCSS}
|
||||
}
|
||||
@@ -111,19 +98,13 @@ const StyledTable = styled.div<{
|
||||
div.table-cell:nth-of-type(1) {
|
||||
left: 0px;
|
||||
position: sticky;
|
||||
z-index: ${({ hasRecordGroups }) =>
|
||||
hasRecordGroups
|
||||
? TABLE_Z_INDEX.cell.withGroups.sticky
|
||||
: TABLE_Z_INDEX.cell.withoutGroups.sticky};
|
||||
z-index: ${TABLE_Z_INDEX.cell.sticky};
|
||||
}
|
||||
|
||||
div.table-cell:nth-of-type(2) {
|
||||
left: ${RECORD_TABLE_COLUMN_DRAG_AND_DROP_WIDTH}px;
|
||||
position: sticky;
|
||||
z-index: ${({ hasRecordGroups }) =>
|
||||
hasRecordGroups
|
||||
? TABLE_Z_INDEX.cell.withGroups.sticky
|
||||
: TABLE_Z_INDEX.cell.withoutGroups.sticky};
|
||||
z-index: ${TABLE_Z_INDEX.cell.sticky};
|
||||
}
|
||||
|
||||
div.table-cell-0-0 {
|
||||
@@ -136,10 +117,7 @@ const StyledTable = styled.div<{
|
||||
div.table-cell:nth-of-type(3) {
|
||||
left: ${`${RECORD_TABLE_COLUMN_DRAG_AND_DROP_WIDTH + RECORD_TABLE_COLUMN_CHECKBOX_WIDTH}px`};
|
||||
position: sticky;
|
||||
z-index: ${({ hasRecordGroups }) =>
|
||||
hasRecordGroups
|
||||
? TABLE_Z_INDEX.cell.withGroups.sticky
|
||||
: TABLE_Z_INDEX.cell.withoutGroups.sticky};
|
||||
z-index: ${TABLE_Z_INDEX.cell.sticky};
|
||||
|
||||
${HorizontalScrollBoxShadowCSS}
|
||||
}
|
||||
|
||||
+9
-49
@@ -1,63 +1,23 @@
|
||||
export const TABLE_Z_INDEX = {
|
||||
base: 1,
|
||||
hoverPortal: 4,
|
||||
headerRow: 10,
|
||||
cell: {
|
||||
withoutGroups: {
|
||||
default: 3,
|
||||
sticky: 12,
|
||||
editMode: 30,
|
||||
},
|
||||
withGroups: {
|
||||
default: 3,
|
||||
sticky: 12,
|
||||
editMode: 30,
|
||||
},
|
||||
default: 3,
|
||||
sticky: 8,
|
||||
editMode: 30,
|
||||
},
|
||||
headerColumns: {
|
||||
withoutGroups: {
|
||||
headerColumnsSticky: 14,
|
||||
headerColumnsNormal: 10,
|
||||
},
|
||||
withGroups: {
|
||||
headerColumnsSticky: 21,
|
||||
headerColumnsNormal: 20,
|
||||
},
|
||||
headerColumnsSticky: 14,
|
||||
headerColumnsNormal: 10,
|
||||
},
|
||||
groupSection: {
|
||||
stickyCell: 10,
|
||||
stickyCell: 9,
|
||||
normalCell: 8,
|
||||
},
|
||||
columnGrip: 30,
|
||||
footer: {
|
||||
tableWithGroups: {
|
||||
default: 17,
|
||||
stickyColumn: 18,
|
||||
},
|
||||
tableWithoutGroups: {
|
||||
default: 18,
|
||||
stickyColumn: 20,
|
||||
},
|
||||
},
|
||||
activeRows: {
|
||||
firstRow: {
|
||||
sticky: {
|
||||
scrolledVertically: 10,
|
||||
noVerticalScroll: 15,
|
||||
},
|
||||
normal: {
|
||||
scrolledVertically: 8,
|
||||
noVerticalScroll: 11,
|
||||
},
|
||||
},
|
||||
afterFirstRow: {
|
||||
sticky: {
|
||||
scrolledVertically: 8,
|
||||
noVerticalScroll: 8,
|
||||
},
|
||||
normal: {
|
||||
scrolledVertically: 7,
|
||||
noVerticalScroll: 7,
|
||||
},
|
||||
},
|
||||
default: 8,
|
||||
stickyColumn: 9,
|
||||
},
|
||||
};
|
||||
|
||||
-1
@@ -37,7 +37,6 @@ export const RecordTableBodyLoading = () => {
|
||||
isDragging={false}
|
||||
data-testid={`row-id-${rowIndex}`}
|
||||
data-selectable-id={`row-id-${rowIndex}`}
|
||||
isFirstRowOfGroup={rowIndex === 0}
|
||||
>
|
||||
<RecordTableCellDragAndDrop />
|
||||
<RecordTableCellCheckbox />
|
||||
|
||||
+3
-5
@@ -68,13 +68,13 @@ const StyledRowDraggableCloneCSSBridge = styled.div`
|
||||
div.table-cell:nth-of-type(1) {
|
||||
left: 0px;
|
||||
position: sticky;
|
||||
z-index: ${TABLE_Z_INDEX.cell.withGroups.sticky};
|
||||
z-index: ${TABLE_Z_INDEX.cell.sticky};
|
||||
}
|
||||
|
||||
div.table-cell:nth-of-type(2) {
|
||||
left: ${RECORD_TABLE_COLUMN_DRAG_AND_DROP_WIDTH}px;
|
||||
position: sticky;
|
||||
z-index: ${TABLE_Z_INDEX.cell.withoutGroups.sticky};
|
||||
z-index: ${TABLE_Z_INDEX.cell.sticky};
|
||||
}
|
||||
|
||||
div.table-cell-0-0 {
|
||||
@@ -87,7 +87,7 @@ const StyledRowDraggableCloneCSSBridge = styled.div`
|
||||
div.table-cell:nth-of-type(3) {
|
||||
left: ${`${RECORD_TABLE_COLUMN_DRAG_AND_DROP_WIDTH + RECORD_TABLE_COLUMN_CHECKBOX_WIDTH}px`};
|
||||
position: sticky;
|
||||
z-index: ${TABLE_Z_INDEX.cell.withoutGroups.sticky};
|
||||
z-index: ${TABLE_Z_INDEX.cell.sticky};
|
||||
|
||||
${HorizontalScrollBoxShadowCSS}
|
||||
}
|
||||
@@ -180,10 +180,8 @@ export const RecordTableBodyVirtualizedDraggableClone = ({
|
||||
}}
|
||||
isDragging={draggableSnapshot.isDragging}
|
||||
data-testid={`row-id-${recordId}`}
|
||||
data-virtualized-id={recordId}
|
||||
data-selectable-id={recordId}
|
||||
onClick={() => {}}
|
||||
isFirstRowOfGroup={false}
|
||||
>
|
||||
<RecordTableRowDraggableContextProvider
|
||||
value={{
|
||||
|
||||
+9
-15
@@ -22,10 +22,6 @@ const StyledContainer = styled.div`
|
||||
width: ${RECORD_TABLE_COLUMN_CHECKBOX_WIDTH};
|
||||
`;
|
||||
|
||||
const StyledRecordTableTdContainer = styled.div`
|
||||
border-left: 1px solid transparent;
|
||||
`;
|
||||
|
||||
export const RecordTableCellCheckbox = () => {
|
||||
const { isSelected } = useRecordTableRowContextOrThrow();
|
||||
|
||||
@@ -42,16 +38,14 @@ export const RecordTableCellCheckbox = () => {
|
||||
);
|
||||
|
||||
return (
|
||||
<StyledRecordTableTdContainer>
|
||||
<RecordTableCellStyleWrapper
|
||||
isSelected={isSelected}
|
||||
hasRightBorder={false}
|
||||
widthClassName={RECORD_TABLE_COLUMN_CHECKBOX_WIDTH_CLASS_NAME}
|
||||
>
|
||||
<StyledContainer onClick={handleClick} data-select-disable>
|
||||
<Checkbox hoverable checked={isSelected} />
|
||||
</StyledContainer>
|
||||
</RecordTableCellStyleWrapper>
|
||||
</StyledRecordTableTdContainer>
|
||||
<RecordTableCellStyleWrapper
|
||||
isSelected={isSelected}
|
||||
hasRightBorder={false}
|
||||
widthClassName={RECORD_TABLE_COLUMN_CHECKBOX_WIDTH_CLASS_NAME}
|
||||
>
|
||||
<StyledContainer onClick={handleClick} data-select-disable>
|
||||
<Checkbox hoverable checked={isSelected} />
|
||||
</StyledContainer>
|
||||
</RecordTableCellStyleWrapper>
|
||||
);
|
||||
};
|
||||
|
||||
+1
-11
@@ -1,8 +1,6 @@
|
||||
import { RecordTableCellPortalWrapper } from '@/object-record/record-table/record-table-cell/components/RecordTableCellPortalWrapper';
|
||||
import { useAtomComponentSelectorValue } from '@/ui/utilities/state/jotai/hooks/useAtomComponentSelectorValue';
|
||||
import { useAtomComponentStateValue } from '@/ui/utilities/state/jotai/hooks/useAtomComponentStateValue';
|
||||
|
||||
import { hasRecordGroupsComponentSelector } from '@/object-record/record-group/states/selectors/hasRecordGroupsComponentSelector';
|
||||
import { TABLE_Z_INDEX } from '@/object-record/record-table/constants/TableZIndex';
|
||||
import { RecordTableCellEditMode } from '@/object-record/record-table/record-table-cell/components/RecordTableCellEditMode';
|
||||
import { RecordTableCellFieldInput } from '@/object-record/record-table/record-table-cell/components/RecordTableCellFieldInput';
|
||||
@@ -22,10 +20,6 @@ export const RecordTableCellEditModePortal = () => {
|
||||
recordTableCellEditModePositionComponentState,
|
||||
);
|
||||
|
||||
const hasRecordGroups = useAtomComponentSelectorValue(
|
||||
hasRecordGroupsComponentSelector,
|
||||
);
|
||||
|
||||
const cellFocusId = useCurrentlyFocusedRecordTableCellFocusId();
|
||||
|
||||
if (!isDefined(recordTableFocusPosition) || !isDefined(cellFocusId)) {
|
||||
@@ -36,11 +30,7 @@ export const RecordTableCellEditModePortal = () => {
|
||||
<RecordTableCellPortalWrapper position={recordTableFocusPosition}>
|
||||
{recordTableCellEditModePosition && (
|
||||
<RecordTableCellPortalRootContainer
|
||||
zIndex={
|
||||
hasRecordGroups
|
||||
? TABLE_Z_INDEX.cell.withGroups.editMode
|
||||
: TABLE_Z_INDEX.cell.withoutGroups.editMode
|
||||
}
|
||||
zIndex={TABLE_Z_INDEX.cell.editMode}
|
||||
>
|
||||
<RecordTableCellEditMode>
|
||||
<RecordTableCellFieldInput />
|
||||
|
||||
+1
-1
@@ -50,7 +50,7 @@ export const RecordTableCellFirstRowFirstColumn = ({
|
||||
} & (Partial<DraggableProvidedDragHandleProps> | null)) => {
|
||||
const { theme } = useContext(ThemeContext);
|
||||
|
||||
const zIndex = TABLE_Z_INDEX.cell.withoutGroups.sticky;
|
||||
const zIndex = TABLE_Z_INDEX.cell.sticky;
|
||||
|
||||
const tdBackgroundColor = isSelected
|
||||
? theme.accent.quaternary
|
||||
|
||||
+17
-33
@@ -8,47 +8,38 @@ import { TABLE_Z_INDEX } from '@/object-record/record-table/constants/TableZInde
|
||||
import { useRecordTableContextOrThrow } from '@/object-record/record-table/contexts/RecordTableContext';
|
||||
import { RecordTableAggregateFooterCell } from '@/object-record/record-table/record-table-footer/components/RecordTableAggregateFooterCell';
|
||||
import { RecordTableColumnAggregateFooterCellContext } from '@/object-record/record-table/record-table-footer/components/RecordTableColumnAggregateFooterCellContext';
|
||||
import { isDefined } from 'twenty-shared/utils';
|
||||
import { themeCssVariables } from 'twenty-ui/theme-constants';
|
||||
|
||||
const StyledPlaceholderDragAndDropFooterCell = styled.div<{
|
||||
isTableWithGroups: boolean;
|
||||
}>`
|
||||
const StyledPlaceholderDragAndDropFooterCell = styled.div`
|
||||
background-color: ${themeCssVariables.background.primary};
|
||||
bottom: 0;
|
||||
left: 0px;
|
||||
position: sticky;
|
||||
width: ${`${RECORD_TABLE_COLUMN_DRAG_AND_DROP_WIDTH + RECORD_TABLE_COLUMN_CHECKBOX_WIDTH}px`};
|
||||
|
||||
z-index: ${({ isTableWithGroups }) =>
|
||||
isTableWithGroups
|
||||
? TABLE_Z_INDEX.footer.tableWithGroups.stickyColumn
|
||||
: TABLE_Z_INDEX.footer.tableWithoutGroups.stickyColumn};
|
||||
z-index: ${TABLE_Z_INDEX.footer.stickyColumn};
|
||||
`;
|
||||
|
||||
const StyledPlaceholderAddButtonPlaceholderFooterCell = styled.div<{
|
||||
isTableWithGroups: boolean;
|
||||
}>`
|
||||
const StyledPlaceholderAddButtonPlaceholderFooterCell = styled.div`
|
||||
background-color: ${themeCssVariables.background.primary};
|
||||
bottom: 0;
|
||||
position: sticky;
|
||||
width: ${RECORD_TABLE_COLUMN_ADD_COLUMN_BUTTON_WIDTH}px;
|
||||
z-index: ${({ isTableWithGroups }) =>
|
||||
isTableWithGroups
|
||||
? TABLE_Z_INDEX.footer.tableWithGroups.default
|
||||
: TABLE_Z_INDEX.footer.tableWithoutGroups.default};
|
||||
z-index: ${TABLE_Z_INDEX.footer.default};
|
||||
`;
|
||||
|
||||
const StyledPlaceholderLastColumnEmptyFooterCell = styled.div<{
|
||||
isTableWithGroups: boolean;
|
||||
}>`
|
||||
const StyledPlaceholderLastColumnEmptyFooterCell = styled.div`
|
||||
background-color: ${themeCssVariables.background.primary};
|
||||
bottom: 0;
|
||||
position: sticky;
|
||||
z-index: ${({ isTableWithGroups }) =>
|
||||
isTableWithGroups
|
||||
? TABLE_Z_INDEX.footer.tableWithGroups.default
|
||||
: TABLE_Z_INDEX.footer.tableWithoutGroups.default};
|
||||
z-index: ${TABLE_Z_INDEX.footer.default};
|
||||
`;
|
||||
|
||||
const StyledAggregateFooterContainer = styled.div`
|
||||
bottom: 0;
|
||||
display: flex;
|
||||
position: sticky;
|
||||
z-index: ${TABLE_Z_INDEX.footer.default};
|
||||
`;
|
||||
|
||||
export const RecordTableAggregateFooter = ({
|
||||
@@ -58,13 +49,9 @@ export const RecordTableAggregateFooter = ({
|
||||
}) => {
|
||||
const { visibleRecordFields } = useRecordTableContextOrThrow();
|
||||
|
||||
const isTableWithGroups = isDefined(currentRecordGroupId);
|
||||
|
||||
return (
|
||||
<>
|
||||
<StyledPlaceholderDragAndDropFooterCell
|
||||
isTableWithGroups={isTableWithGroups}
|
||||
/>
|
||||
<StyledAggregateFooterContainer>
|
||||
<StyledPlaceholderDragAndDropFooterCell />
|
||||
{visibleRecordFields.map((recordField, index) => {
|
||||
return (
|
||||
<RecordTableColumnAggregateFooterCellContext.Provider
|
||||
@@ -81,13 +68,10 @@ export const RecordTableAggregateFooter = ({
|
||||
</RecordTableColumnAggregateFooterCellContext.Provider>
|
||||
);
|
||||
})}
|
||||
<StyledPlaceholderAddButtonPlaceholderFooterCell
|
||||
isTableWithGroups={isTableWithGroups}
|
||||
/>
|
||||
<StyledPlaceholderAddButtonPlaceholderFooterCell />
|
||||
<StyledPlaceholderLastColumnEmptyFooterCell
|
||||
isTableWithGroups={isTableWithGroups}
|
||||
className={RECORD_TABLE_COLUMN_LAST_EMPTY_COLUMN_WIDTH_CLASS_NAME}
|
||||
/>
|
||||
</>
|
||||
</StyledAggregateFooterContainer>
|
||||
);
|
||||
};
|
||||
|
||||
+6
-12
@@ -1,6 +1,6 @@
|
||||
import { styled } from '@linaria/react';
|
||||
import { useContext } from 'react';
|
||||
import { themeCssVariables, MOBILE_VIEWPORT } from 'twenty-ui/theme-constants';
|
||||
import { MOBILE_VIEWPORT, themeCssVariables } from 'twenty-ui/theme-constants';
|
||||
|
||||
import { RECORD_TABLE_COLUMN_CHECKBOX_WIDTH } from '@/object-record/record-table/constants/RecordTableColumnCheckboxWidth';
|
||||
import { RECORD_TABLE_COLUMN_DRAG_AND_DROP_WIDTH } from '@/object-record/record-table/constants/RecordTableColumnDragAndDropWidth';
|
||||
@@ -17,7 +17,6 @@ import { findByProperty, isDefined } from 'twenty-shared/utils';
|
||||
const StyledColumnFooterCell = styled.div<{
|
||||
columnWidth: number;
|
||||
isFirstCell: boolean;
|
||||
isTableWithGroups: boolean;
|
||||
}>`
|
||||
background-color: ${themeCssVariables.background.primary};
|
||||
border-right: solid 1px ${themeCssVariables.background.primary};
|
||||
@@ -31,6 +30,7 @@ const StyledColumnFooterCell = styled.div<{
|
||||
isFirstCell
|
||||
? `${RECORD_TABLE_COLUMN_DRAG_AND_DROP_WIDTH + RECORD_TABLE_COLUMN_CHECKBOX_WIDTH}px`
|
||||
: 'auto'};
|
||||
|
||||
min-width: ${({ columnWidth }) => columnWidth}px;
|
||||
&:hover {
|
||||
background: ${themeCssVariables.background.secondary};
|
||||
@@ -43,14 +43,11 @@ const StyledColumnFooterCell = styled.div<{
|
||||
text-align: left;
|
||||
|
||||
width: ${({ columnWidth }) => columnWidth}px;
|
||||
z-index: ${({ isFirstCell, isTableWithGroups }) =>
|
||||
|
||||
z-index: ${({ isFirstCell }) =>
|
||||
isFirstCell
|
||||
? isTableWithGroups
|
||||
? TABLE_Z_INDEX.footer.tableWithGroups.stickyColumn
|
||||
: TABLE_Z_INDEX.footer.tableWithoutGroups.stickyColumn
|
||||
: isTableWithGroups
|
||||
? TABLE_Z_INDEX.footer.tableWithGroups.default
|
||||
: TABLE_Z_INDEX.footer.tableWithoutGroups.default};
|
||||
? TABLE_Z_INDEX.footer.stickyColumn
|
||||
: TABLE_Z_INDEX.footer.default};
|
||||
|
||||
@media (max-width: ${MOBILE_VIEWPORT}px) {
|
||||
max-width: ${({ isFirstCell }) =>
|
||||
@@ -91,8 +88,6 @@ export const RecordTableAggregateFooterCell = ({
|
||||
findByProperty('fieldMetadataItemId', fieldMetadataId),
|
||||
);
|
||||
|
||||
const isTableWithGroups = isDefined(currentRecordGroupId);
|
||||
|
||||
const isFirstCell = columnIndex === 0;
|
||||
|
||||
if (!isDefined(recordField)) {
|
||||
@@ -107,7 +102,6 @@ export const RecordTableAggregateFooterCell = ({
|
||||
'footer-cell',
|
||||
getRecordTableColumnFieldWidthClassName(columnIndex),
|
||||
)}
|
||||
isTableWithGroups={isTableWithGroups}
|
||||
>
|
||||
<StyledColumnFootContainer>
|
||||
<RecordTableColumnFooterWithDropdown
|
||||
|
||||
+12
-2
@@ -1,4 +1,5 @@
|
||||
import { useRecordIndexContextOrThrow } from '@/object-record/record-index/contexts/RecordIndexContext';
|
||||
import { TABLE_Z_INDEX } from '@/object-record/record-table/constants/TableZIndex';
|
||||
import { useRecordTableContextOrThrow } from '@/object-record/record-table/contexts/RecordTableContext';
|
||||
import { RecordTableHeaderAddColumnButton } from '@/object-record/record-table/record-table-header/components/RecordTableHeaderAddColumnButton';
|
||||
import { RecordTableHeaderCell } from '@/object-record/record-table/record-table-header/components/RecordTableHeaderCell';
|
||||
@@ -8,8 +9,17 @@ import { RecordTableHeaderFirstCell } from '@/object-record/record-table/record-
|
||||
import { RecordTableHeaderFirstScrollableCell } from '@/object-record/record-table/record-table-header/components/RecordTableHeaderFirstScrollableCell';
|
||||
import { RecordTableHeaderLastEmptyColumn } from '@/object-record/record-table/record-table-header/components/RecordTableHeaderLastEmptyColumn';
|
||||
import { useResizeTableHeader } from '@/object-record/record-table/record-table-header/hooks/useResizeTableHeader';
|
||||
import { styled } from '@linaria/react';
|
||||
import { filterOutByProperty } from 'twenty-shared/utils';
|
||||
|
||||
const StyledHeaderContainer = styled.div`
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
position: sticky;
|
||||
top: 0;
|
||||
z-index: ${TABLE_Z_INDEX.headerRow};
|
||||
`;
|
||||
|
||||
export const RecordTableHeader = () => {
|
||||
const { visibleRecordFields } = useRecordTableContextOrThrow();
|
||||
const { labelIdentifierFieldMetadataItem } = useRecordIndexContextOrThrow();
|
||||
@@ -26,7 +36,7 @@ export const RecordTableHeader = () => {
|
||||
useResizeTableHeader();
|
||||
|
||||
return (
|
||||
<>
|
||||
<StyledHeaderContainer>
|
||||
<RecordTableHeaderDragDropColumn />
|
||||
<RecordTableHeaderCheckboxColumn />
|
||||
<RecordTableHeaderFirstCell />
|
||||
@@ -42,6 +52,6 @@ export const RecordTableHeader = () => {
|
||||
)}
|
||||
<RecordTableHeaderAddColumnButton />
|
||||
<RecordTableHeaderLastEmptyColumn />
|
||||
</>
|
||||
</StyledHeaderContainer>
|
||||
);
|
||||
};
|
||||
|
||||
+1
-1
@@ -16,8 +16,8 @@ import { isRecordTableRowFocusActiveComponentState } from '@/object-record/recor
|
||||
import { isRecordTableRowFocusedComponentFamilyState } from '@/object-record/record-table/states/isRecordTableRowFocusedComponentFamilyState';
|
||||
import { isRecordTableScrolledVerticallyComponentState } from '@/object-record/record-table/states/isRecordTableScrolledVerticallyComponentState';
|
||||
import { allRowsSelectedStatusComponentSelector } from '@/object-record/record-table/states/selectors/allRowsSelectedStatusComponentSelector';
|
||||
import { useAtomComponentSelectorValue } from '@/ui/utilities/state/jotai/hooks/useAtomComponentSelectorValue';
|
||||
import { useAtomComponentFamilyStateValue } from '@/ui/utilities/state/jotai/hooks/useAtomComponentFamilyStateValue';
|
||||
import { useAtomComponentSelectorValue } from '@/ui/utilities/state/jotai/hooks/useAtomComponentSelectorValue';
|
||||
import { useAtomComponentStateValue } from '@/ui/utilities/state/jotai/hooks/useAtomComponentStateValue';
|
||||
import { cx } from '@linaria/core';
|
||||
import { Checkbox } from 'twenty-ui/input';
|
||||
|
||||
+1
-1
@@ -27,7 +27,7 @@ const StyledPlusButtonWrapper = styled.div`
|
||||
position: absolute;
|
||||
right: 0;
|
||||
top: 0;
|
||||
z-index: ${TABLE_Z_INDEX.headerColumns.withoutGroups.headerColumnsSticky};
|
||||
z-index: ${TABLE_Z_INDEX.headerColumns.headerColumnsSticky};
|
||||
`;
|
||||
|
||||
export const RecordTableHeaderFirstCell = () => {
|
||||
|
||||
+1
-5
@@ -59,10 +59,6 @@ export const RecordTableHeaderFirstScrollableCell = () => {
|
||||
hasRecordGroupsComponentSelector,
|
||||
);
|
||||
|
||||
const zIndex = hasRecordGroups
|
||||
? TABLE_Z_INDEX.headerColumns.withGroups.headerColumnsNormal
|
||||
: TABLE_Z_INDEX.headerColumns.withoutGroups.headerColumnsNormal;
|
||||
|
||||
const shouldDisplayBorderBottom =
|
||||
hasRecordGroups ||
|
||||
!isFirstRowActiveOrFocused ||
|
||||
@@ -83,7 +79,7 @@ export const RecordTableHeaderFirstScrollableCell = () => {
|
||||
className={cx('header-cell', getRecordTableColumnFieldWidthClassName(1))}
|
||||
key={recordField.fieldMetadataItemId}
|
||||
shouldDisplayBorderBottom={shouldDisplayBorderBottom}
|
||||
zIndex={zIndex}
|
||||
zIndex={TABLE_Z_INDEX.headerColumns.headerColumnsNormal}
|
||||
isResizing={isResizingAnyColumn}
|
||||
>
|
||||
<RecordTableHeaderResizeHandler recordFieldIndex={1} position="left" />
|
||||
|
||||
-2
@@ -58,10 +58,8 @@ export const RecordTableDraggableTr = ({
|
||||
}}
|
||||
isDragging={draggableSnapshot.isDragging}
|
||||
data-testid={`row-id-${recordId}`}
|
||||
data-virtualized-id={recordId}
|
||||
data-selectable-id={recordId}
|
||||
onClick={onClick}
|
||||
isFirstRowOfGroup={false}
|
||||
>
|
||||
<RecordTableRowDraggableContextProvider
|
||||
value={{
|
||||
|
||||
-87
@@ -1,87 +0,0 @@
|
||||
import { Draggable } from '@hello-pangea/dnd';
|
||||
import { type ReactNode, useContext } from 'react';
|
||||
import { ThemeContext } from 'twenty-ui/theme-constants';
|
||||
|
||||
import { RecordTableRowDraggableContextProvider } from '@/object-record/record-table/contexts/RecordTableRowDraggableContext';
|
||||
import { RecordTableRowMultiDragPreview } from '@/object-record/record-table/record-table-row/components/RecordTableRowMultiDragPreview';
|
||||
import { RecordTableTr } from '@/object-record/record-table/record-table-row/components/RecordTableTr';
|
||||
|
||||
import { useIsTableRowSecondaryDragged } from '@/object-record/record-table/record-table-row/hooks/useIsRecordSecondaryDragged';
|
||||
import { isRecordTableScrolledVerticallyComponentState } from '@/object-record/record-table/states/isRecordTableScrolledVerticallyComponentState';
|
||||
import { useAtomComponentStateValue } from '@/ui/utilities/state/jotai/hooks/useAtomComponentStateValue';
|
||||
|
||||
type RecordTableDraggableTrFirstRowOfGroupProps = {
|
||||
className?: string;
|
||||
recordId: string;
|
||||
draggableIndex: number;
|
||||
focusIndex: number;
|
||||
isDragDisabled?: boolean;
|
||||
onClick?: (event: React.MouseEvent<HTMLTableRowElement>) => void;
|
||||
children: ReactNode;
|
||||
};
|
||||
|
||||
export const RecordTableDraggableTrFirstRowOfGroup = ({
|
||||
className,
|
||||
recordId,
|
||||
draggableIndex,
|
||||
focusIndex,
|
||||
isDragDisabled,
|
||||
onClick,
|
||||
children,
|
||||
}: RecordTableDraggableTrFirstRowOfGroupProps) => {
|
||||
const { theme } = useContext(ThemeContext);
|
||||
|
||||
const { isSecondaryDragged } = useIsTableRowSecondaryDragged(recordId);
|
||||
|
||||
const isRecordTableScrolledVertically = useAtomComponentStateValue(
|
||||
isRecordTableScrolledVerticallyComponentState,
|
||||
);
|
||||
|
||||
return (
|
||||
<Draggable
|
||||
draggableId={recordId}
|
||||
index={draggableIndex}
|
||||
isDragDisabled={isDragDisabled}
|
||||
>
|
||||
{(draggableProvided, draggableSnapshot) => (
|
||||
<>
|
||||
<RecordTableTr
|
||||
recordId={recordId}
|
||||
focusIndex={focusIndex}
|
||||
ref={draggableProvided.innerRef}
|
||||
className={className}
|
||||
// oxlint-disable-next-line react/jsx-props-no-spreading
|
||||
{...draggableProvided.draggableProps}
|
||||
style={{
|
||||
...draggableProvided.draggableProps.style,
|
||||
background: draggableSnapshot.isDragging
|
||||
? theme.background.transparent.light
|
||||
: undefined,
|
||||
borderColor: draggableSnapshot.isDragging
|
||||
? `${theme.border.color.medium}`
|
||||
: 'transparent',
|
||||
opacity: isSecondaryDragged ? 0.3 : undefined,
|
||||
}}
|
||||
isDragging={draggableSnapshot.isDragging}
|
||||
data-testid={`row-id-${recordId}`}
|
||||
data-virtualized-id={recordId}
|
||||
data-selectable-id={recordId}
|
||||
onClick={onClick}
|
||||
isFirstRowOfGroup={true}
|
||||
isScrolledVertically={isRecordTableScrolledVertically}
|
||||
>
|
||||
<RecordTableRowDraggableContextProvider
|
||||
value={{
|
||||
isDragging: draggableSnapshot.isDragging,
|
||||
dragHandleProps: draggableProvided.dragHandleProps,
|
||||
}}
|
||||
>
|
||||
{children}
|
||||
<RecordTableRowMultiDragPreview />
|
||||
</RecordTableRowDraggableContextProvider>
|
||||
</RecordTableTr>
|
||||
</>
|
||||
)}
|
||||
</Draggable>
|
||||
);
|
||||
};
|
||||
+15
-46
@@ -1,57 +1,26 @@
|
||||
import { RecordTableRowDiv } from '@/object-record/record-table/record-table-row/components/RecordTableRowDiv';
|
||||
import { isRecordTableScrolledVerticallyComponentState } from '@/object-record/record-table/states/isRecordTableScrolledVerticallyComponentState';
|
||||
import { useAtomComponentStateValue } from '@/ui/utilities/state/jotai/hooks/useAtomComponentStateValue';
|
||||
import { forwardRef, type ReactNode } from 'react';
|
||||
|
||||
type RecordTableTrProps = {
|
||||
children: ReactNode;
|
||||
recordId: string;
|
||||
focusIndex: number;
|
||||
isDragging?: boolean;
|
||||
isRowFocusActive: boolean;
|
||||
isFocused: boolean;
|
||||
isNextRowActiveOrFocused: boolean;
|
||||
} & Omit<
|
||||
React.ComponentProps<typeof RecordTableRowDiv>,
|
||||
'isActive' | 'isNextRowActiveOrFocused' | 'isFocused'
|
||||
>;
|
||||
};
|
||||
|
||||
export const RecordTableFirstRowOfGroup = forwardRef<
|
||||
HTMLDivElement,
|
||||
RecordTableTrProps
|
||||
>(
|
||||
(
|
||||
{
|
||||
children,
|
||||
recordId,
|
||||
isNextRowActiveOrFocused,
|
||||
isDragging = false,
|
||||
isRowFocusActive,
|
||||
isFocused,
|
||||
...props
|
||||
},
|
||||
ref,
|
||||
) => {
|
||||
const isRecordTableScrolledVertically = useAtomComponentStateValue(
|
||||
isRecordTableScrolledVerticallyComponentState,
|
||||
);
|
||||
|
||||
return (
|
||||
<RecordTableRowDiv
|
||||
className="table-row"
|
||||
data-virtualized-id={recordId}
|
||||
isDragging={isDragging}
|
||||
ref={ref}
|
||||
data-active={false}
|
||||
data-focused={isRowFocusActive && isFocused}
|
||||
data-next-row-active-or-focused={isNextRowActiveOrFocused}
|
||||
// oxlint-disable-next-line react/jsx-props-no-spreading
|
||||
{...props}
|
||||
isScrolledVertically={isRecordTableScrolledVertically}
|
||||
isFirstRowOfGroup={true}
|
||||
>
|
||||
{children}
|
||||
</RecordTableRowDiv>
|
||||
);
|
||||
},
|
||||
);
|
||||
>(({ children, recordId, isDragging = false, ...props }, ref) => {
|
||||
return (
|
||||
<RecordTableRowDiv
|
||||
className="table-row"
|
||||
data-virtualized-id={recordId}
|
||||
isDragging={isDragging}
|
||||
ref={ref}
|
||||
// oxlint-disable-next-line react/jsx-props-no-spreading
|
||||
{...props}
|
||||
>
|
||||
{children}
|
||||
</RecordTableRowDiv>
|
||||
);
|
||||
});
|
||||
|
||||
+3
-23
@@ -3,12 +3,11 @@ import { RecordTableCellDragAndDrop } from '@/object-record/record-table/record-
|
||||
import { RecordTableLastEmptyCell } from '@/object-record/record-table/record-table-cell/components/RecordTableLastEmptyCell';
|
||||
import { RecordTablePlusButtonCellPlaceholder } from '@/object-record/record-table/record-table-cell/components/RecordTablePlusButtonCellPlaceholder';
|
||||
|
||||
import { useRecordTableContextOrThrow } from '@/object-record/record-table/contexts/RecordTableContext';
|
||||
import { RecordTableDraggableTr } from '@/object-record/record-table/record-table-row/components/RecordTableDraggableTr';
|
||||
import { RecordTableDraggableTrFirstRowOfGroup } from '@/object-record/record-table/record-table-row/components/RecordTableDraggableTrFirstRowOfGroup';
|
||||
import { RecordTableFieldsCells } from '@/object-record/record-table/record-table-row/components/RecordTableFieldsCells';
|
||||
import { RecordTableRowArrowKeysEffect } from '@/object-record/record-table/record-table-row/components/RecordTableRowArrowKeysEffect';
|
||||
import { RecordTableRowHotkeyEffect } from '@/object-record/record-table/record-table-row/components/RecordTableRowHotkeyEffect';
|
||||
import { useRecordTableContextOrThrow } from '@/object-record/record-table/contexts/RecordTableContext';
|
||||
import { isRecordTableRowFocusActiveComponentState } from '@/object-record/record-table/states/isRecordTableRowFocusActiveComponentState';
|
||||
import { isRecordTableRowFocusedComponentFamilyState } from '@/object-record/record-table/states/isRecordTableRowFocusedComponentFamilyState';
|
||||
import { useAtomComponentFamilyStateValue } from '@/ui/utilities/state/jotai/hooks/useAtomComponentFamilyStateValue';
|
||||
@@ -18,14 +17,12 @@ type RecordTableRowProps = {
|
||||
recordId: string;
|
||||
rowIndexForFocus: number;
|
||||
rowIndexForDrag: number;
|
||||
isFirstRowOfGroup: boolean;
|
||||
};
|
||||
|
||||
export const RecordTableRow = ({
|
||||
recordId,
|
||||
rowIndexForFocus,
|
||||
rowIndexForDrag,
|
||||
isFirstRowOfGroup,
|
||||
}: RecordTableRowProps) => {
|
||||
const { recordTableId } = useRecordTableContextOrThrow();
|
||||
|
||||
@@ -33,30 +30,13 @@ export const RecordTableRow = ({
|
||||
isRecordTableRowFocusedComponentFamilyState,
|
||||
rowIndexForFocus,
|
||||
);
|
||||
|
||||
const isRecordTableRowFocusActive = useAtomComponentStateValue(
|
||||
isRecordTableRowFocusActiveComponentState,
|
||||
recordTableId,
|
||||
);
|
||||
|
||||
return isFirstRowOfGroup ? (
|
||||
<RecordTableDraggableTrFirstRowOfGroup
|
||||
recordId={recordId}
|
||||
draggableIndex={rowIndexForDrag}
|
||||
focusIndex={rowIndexForFocus}
|
||||
>
|
||||
{isRecordTableRowFocusActive && isRecordTableRowFocused && (
|
||||
<>
|
||||
<RecordTableRowHotkeyEffect />
|
||||
<RecordTableRowArrowKeysEffect />
|
||||
</>
|
||||
)}
|
||||
<RecordTableCellDragAndDrop />
|
||||
<RecordTableCellCheckbox />
|
||||
<RecordTableFieldsCells />
|
||||
<RecordTablePlusButtonCellPlaceholder />
|
||||
<RecordTableLastEmptyCell />
|
||||
</RecordTableDraggableTrFirstRowOfGroup>
|
||||
) : (
|
||||
return (
|
||||
<RecordTableDraggableTr
|
||||
recordId={recordId}
|
||||
draggableIndex={rowIndexForDrag}
|
||||
|
||||
-27
@@ -1,36 +1,9 @@
|
||||
import { TABLE_Z_INDEX } from '@/object-record/record-table/constants/TableZIndex';
|
||||
import { styled } from '@linaria/react';
|
||||
import { themeCssVariables } from 'twenty-ui/theme-constants';
|
||||
|
||||
const StyledTr = styled.div<{
|
||||
isDragging: boolean;
|
||||
isFirstRowOfGroup?: boolean;
|
||||
isScrolledVertically?: boolean;
|
||||
}>`
|
||||
--z-index-for-normal-cells: ${({
|
||||
isFirstRowOfGroup,
|
||||
isScrolledVertically,
|
||||
}) =>
|
||||
isFirstRowOfGroup === true
|
||||
? isScrolledVertically
|
||||
? TABLE_Z_INDEX.activeRows.firstRow.normal.scrolledVertically
|
||||
: TABLE_Z_INDEX.activeRows.firstRow.normal.noVerticalScroll
|
||||
: isScrolledVertically
|
||||
? TABLE_Z_INDEX.activeRows.afterFirstRow.normal.scrolledVertically
|
||||
: TABLE_Z_INDEX.activeRows.afterFirstRow.normal.noVerticalScroll};
|
||||
|
||||
--z-index-for-sticky-cells: ${({
|
||||
isFirstRowOfGroup,
|
||||
isScrolledVertically,
|
||||
}) =>
|
||||
isFirstRowOfGroup === true
|
||||
? isScrolledVertically
|
||||
? TABLE_Z_INDEX.activeRows.firstRow.sticky.scrolledVertically
|
||||
: TABLE_Z_INDEX.activeRows.firstRow.sticky.noVerticalScroll
|
||||
: isScrolledVertically
|
||||
? TABLE_Z_INDEX.activeRows.afterFirstRow.sticky.scrolledVertically
|
||||
: TABLE_Z_INDEX.activeRows.afterFirstRow.sticky.noVerticalScroll};
|
||||
|
||||
border-top: ${({ isDragging }) =>
|
||||
isDragging ? `1px solid ${themeCssVariables.border.color.medium}` : 'none'};
|
||||
|
||||
|
||||
+17
-85
@@ -2,42 +2,28 @@ import { getBasePathToShowPage } from '@/object-metadata/utils/getBasePathToShow
|
||||
import { useIsRecordReadOnly } from '@/object-record/read-only/hooks/useIsRecordReadOnly';
|
||||
import { useRecordTableContextOrThrow } from '@/object-record/record-table/contexts/RecordTableContext';
|
||||
import { RecordTableRowContextProvider } from '@/object-record/record-table/contexts/RecordTableRowContext';
|
||||
import { RecordTableFirstRowOfGroup } from '@/object-record/record-table/record-table-row/components/RecordTableFirstRowOfGroup';
|
||||
import { RecordTableRowDiv } from '@/object-record/record-table/record-table-row/components/RecordTableRowDiv';
|
||||
import { isRecordIdFirstOfGroupComponentFamilySelector } from '@/object-record/record-table/record-table-row/states/isRecordIdFirstOfGroupComponentFamilySelector';
|
||||
import { isRowSelectedComponentFamilyState } from '@/object-record/record-table/record-table-row/states/isRowSelectedComponentFamilyState';
|
||||
import { isRecordTableRowActiveComponentFamilyState } from '@/object-record/record-table/states/isRecordTableRowActiveComponentFamilyState';
|
||||
import { isRecordTableRowFocusActiveComponentState } from '@/object-record/record-table/states/isRecordTableRowFocusActiveComponentState';
|
||||
import { isRecordTableRowFocusedComponentFamilyState } from '@/object-record/record-table/states/isRecordTableRowFocusedComponentFamilyState';
|
||||
import { recordIdByRealIndexComponentFamilySelector } from '@/object-record/record-table/virtualization/states/recordIdByRealIndexComponentFamilySelector';
|
||||
|
||||
import { useAtomComponentFamilySelectorValue } from '@/ui/utilities/state/jotai/hooks/useAtomComponentFamilySelectorValue';
|
||||
import { useAtomComponentFamilyStateValue } from '@/ui/utilities/state/jotai/hooks/useAtomComponentFamilyStateValue';
|
||||
import { useAtomComponentStateValue } from '@/ui/utilities/state/jotai/hooks/useAtomComponentStateValue';
|
||||
import { forwardRef, type ReactNode } from 'react';
|
||||
|
||||
type RecordTableTrProps = {
|
||||
children: ReactNode;
|
||||
recordId: string;
|
||||
focusIndex: number;
|
||||
isDragging?: boolean;
|
||||
isFirstRowOfGroup?: boolean;
|
||||
} & Omit<
|
||||
React.ComponentProps<typeof RecordTableRowDiv>,
|
||||
'isActive' | 'isNextRowActiveOrFocused' | 'isFocused'
|
||||
>;
|
||||
|
||||
export const RecordTableTr = forwardRef<HTMLDivElement, RecordTableTrProps>(
|
||||
(
|
||||
{
|
||||
children,
|
||||
recordId,
|
||||
focusIndex,
|
||||
isDragging = false,
|
||||
isFirstRowOfGroup,
|
||||
...props
|
||||
},
|
||||
ref,
|
||||
) => {
|
||||
({ children, recordId, focusIndex, isDragging = false, ...props }, ref) => {
|
||||
const { objectMetadataItem } = useRecordTableContextOrThrow();
|
||||
|
||||
const isRowSelected = useAtomComponentFamilyStateValue(
|
||||
@@ -50,22 +36,6 @@ export const RecordTableTr = forwardRef<HTMLDivElement, RecordTableTrProps>(
|
||||
focusIndex,
|
||||
);
|
||||
|
||||
// oxlint-disable-next-line twenty/matching-state-variable
|
||||
const isNextRecordTableRowActive = useAtomComponentFamilyStateValue(
|
||||
isRecordTableRowActiveComponentFamilyState,
|
||||
focusIndex + 1,
|
||||
);
|
||||
|
||||
const nextRecordId = useAtomComponentFamilySelectorValue(
|
||||
recordIdByRealIndexComponentFamilySelector,
|
||||
focusIndex + 1,
|
||||
);
|
||||
|
||||
const isNextRecordIdFirstOfGroup = useAtomComponentFamilySelectorValue(
|
||||
isRecordIdFirstOfGroupComponentFamilySelector,
|
||||
nextRecordId ?? '',
|
||||
);
|
||||
|
||||
const isRecordTableRowFocused = useAtomComponentFamilyStateValue(
|
||||
isRecordTableRowFocusedComponentFamilyState,
|
||||
focusIndex,
|
||||
@@ -75,17 +45,6 @@ export const RecordTableTr = forwardRef<HTMLDivElement, RecordTableTrProps>(
|
||||
isRecordTableRowFocusActiveComponentState,
|
||||
);
|
||||
|
||||
// oxlint-disable-next-line twenty/matching-state-variable
|
||||
const isNextRecordTableRowFocused = useAtomComponentFamilyStateValue(
|
||||
isRecordTableRowFocusedComponentFamilyState,
|
||||
focusIndex + 1,
|
||||
);
|
||||
|
||||
const isNextRowActiveOrFocused =
|
||||
!isNextRecordIdFirstOfGroup &&
|
||||
((isRecordTableRowFocusActive && isNextRecordTableRowFocused) ||
|
||||
isNextRecordTableRowActive);
|
||||
|
||||
const isRecordReadOnly = useIsRecordReadOnly({
|
||||
recordId,
|
||||
objectMetadataId: objectMetadataItem.id,
|
||||
@@ -105,48 +64,21 @@ export const RecordTableTr = forwardRef<HTMLDivElement, RecordTableTrProps>(
|
||||
isRecordReadOnly,
|
||||
}}
|
||||
>
|
||||
{isFirstRowOfGroup ? (
|
||||
<RecordTableFirstRowOfGroup
|
||||
className="table-row"
|
||||
data-virtualized-id={recordId}
|
||||
isDragging={isDragging}
|
||||
ref={ref}
|
||||
data-active={isRecordTableRowActive}
|
||||
data-focused={
|
||||
isRecordTableRowFocusActive &&
|
||||
isRecordTableRowFocused &&
|
||||
!isRecordTableRowActive
|
||||
}
|
||||
data-next-row-active-or-focused={isNextRowActiveOrFocused}
|
||||
isNextRowActiveOrFocused={isNextRowActiveOrFocused}
|
||||
focusIndex={focusIndex}
|
||||
isFocused={isRecordTableRowFocused}
|
||||
isRowFocusActive={isRecordTableRowFocusActive}
|
||||
recordId={recordId}
|
||||
// oxlint-disable-next-line react/jsx-props-no-spreading
|
||||
{...props}
|
||||
>
|
||||
{children}
|
||||
</RecordTableFirstRowOfGroup>
|
||||
) : (
|
||||
<RecordTableRowDiv
|
||||
className="table-row"
|
||||
data-virtualized-id={recordId}
|
||||
isDragging={isDragging}
|
||||
ref={ref}
|
||||
data-active={isRecordTableRowActive}
|
||||
data-focused={
|
||||
isRecordTableRowFocusActive &&
|
||||
isRecordTableRowFocused &&
|
||||
!isRecordTableRowActive
|
||||
}
|
||||
data-next-row-active-or-focused={isNextRowActiveOrFocused}
|
||||
// oxlint-disable-next-line react/jsx-props-no-spreading
|
||||
{...props}
|
||||
>
|
||||
{children}
|
||||
</RecordTableRowDiv>
|
||||
)}
|
||||
<RecordTableRowDiv
|
||||
className="table-row"
|
||||
isDragging={isDragging}
|
||||
ref={ref}
|
||||
data-active={isRecordTableRowActive}
|
||||
data-focused={
|
||||
isRecordTableRowFocusActive &&
|
||||
isRecordTableRowFocused &&
|
||||
!isRecordTableRowActive
|
||||
}
|
||||
// oxlint-disable-next-line react/jsx-props-no-spreading
|
||||
{...props}
|
||||
>
|
||||
{children}
|
||||
</RecordTableRowDiv>
|
||||
</RecordTableRowContextProvider>
|
||||
);
|
||||
},
|
||||
|
||||
+1
-1
@@ -44,7 +44,7 @@ const StyledTrContainer = styled.div`
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
|
||||
div:not(:first-of-type) {
|
||||
> div:not(:first-of-type) {
|
||||
border-bottom: 1px solid ${themeCssVariables.border.color.light};
|
||||
}
|
||||
`;
|
||||
|
||||
+1
-1
@@ -18,7 +18,7 @@ export const computeLastRecordTableColumnWidth = ({
|
||||
visibleRecordFields: recordFields,
|
||||
});
|
||||
|
||||
const widthOfBorders = recordFields.length;
|
||||
const widthOfBorders = recordFields.length + 1;
|
||||
|
||||
const fixedColumnsWidth =
|
||||
RECORD_TABLE_COLUMN_DRAG_AND_DROP_WIDTH +
|
||||
|
||||
+6
-6
@@ -1,3 +1,4 @@
|
||||
import { useRecordTableContextOrThrow } from '@/object-record/record-table/contexts/RecordTableContext';
|
||||
import { RecordTableCellCheckbox } from '@/object-record/record-table/record-table-cell/components/RecordTableCellCheckbox';
|
||||
import { RecordTableCellDragAndDrop } from '@/object-record/record-table/record-table-cell/components/RecordTableCellDragAndDrop';
|
||||
import { RecordTableLastEmptyCell } from '@/object-record/record-table/record-table-cell/components/RecordTableLastEmptyCell';
|
||||
@@ -6,7 +7,6 @@ import { RecordTableDraggableTr } from '@/object-record/record-table/record-tabl
|
||||
import { RecordTableFieldsCells } from '@/object-record/record-table/record-table-row/components/RecordTableFieldsCells';
|
||||
import { RecordTableRowArrowKeysEffect } from '@/object-record/record-table/record-table-row/components/RecordTableRowArrowKeysEffect';
|
||||
import { RecordTableRowHotkeyEffect } from '@/object-record/record-table/record-table-row/components/RecordTableRowHotkeyEffect';
|
||||
import { useRecordTableContextOrThrow } from '@/object-record/record-table/contexts/RecordTableContext';
|
||||
import { isRecordTableRowFocusActiveComponentState } from '@/object-record/record-table/states/isRecordTableRowFocusActiveComponentState';
|
||||
import { isRecordTableRowFocusedComponentFamilyState } from '@/object-record/record-table/states/isRecordTableRowFocusedComponentFamilyState';
|
||||
import { RecordTableRowVirtualizedSkeleton } from '@/object-record/record-table/virtualization/components/RecordTableRowVirtualizedSkeleton';
|
||||
@@ -52,17 +52,17 @@ export const RecordTableRowVirtualizedFullData = ({
|
||||
draggableIndex={realIndex}
|
||||
focusIndex={realIndex}
|
||||
>
|
||||
<RecordTableCellDragAndDrop />
|
||||
<RecordTableCellCheckbox />
|
||||
<RecordTableFieldsCells />
|
||||
<RecordTablePlusButtonCellPlaceholder />
|
||||
<RecordTableLastEmptyCell />
|
||||
{isRecordTableRowFocusActive && isRecordTableRowFocused && (
|
||||
<>
|
||||
<RecordTableRowHotkeyEffect />
|
||||
<RecordTableRowArrowKeysEffect />
|
||||
</>
|
||||
)}
|
||||
<RecordTableCellDragAndDrop />
|
||||
<RecordTableCellCheckbox />
|
||||
<RecordTableFieldsCells />
|
||||
<RecordTablePlusButtonCellPlaceholder />
|
||||
<RecordTableLastEmptyCell />
|
||||
</RecordTableDraggableTr>
|
||||
);
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user