839 Table focus refactoring (#11629)

# Table Focus Refactoring

This pull request implements the table focus refactoring requested in
[#839](https://github.com/twentyhq/core-team-issues/issues/839),
dissociating hover and focus behaviors in the table component to improve
keyboard navigation.

## Technical Implementation

- Created separate component states to handle focus and hover
independently.
- Updated all relevant hooks and functions to use the new focus
mechanism.
- Removed deprecated states and hooks.
- Introduced dedicated portal components to improve the table
performance (the table cells are much simpler and the more complex logic
is handled via the portals)

## Key Behavior Changes

- Performance improvements
- Focus is now handled exclusively with keyboard navigation
- Clicking on a cell or inline-cell now sets the focus to that cell
- Hover state is managed separately from focus, improving user
experience and accessibility
- The table scrolls when the focused cell changes

## Video



https://github.com/user-attachments/assets/9966beac-3b0f-4433-a87a-299506d83353
This commit is contained in:
Raphaël Bosi
2025-04-17 18:40:24 +02:00
committed by GitHub
parent 18a89b5152
commit dd0ea2366f
72 changed files with 920 additions and 1150 deletions

View File

@ -6,9 +6,11 @@ import { recordIndexAllRecordIdsComponentSelector } from '@/object-record/record
import { RecordTableBodyEffectsWrapper } from '@/object-record/record-table/components/RecordTableBodyEffectsWrapper';
import { RecordTableContent } from '@/object-record/record-table/components/RecordTableContent';
import { RecordTableEmpty } from '@/object-record/record-table/components/RecordTableEmpty';
import { RecordTableScrollToFocusedElementEffect } from '@/object-record/record-table/components/RecordTableScrollToFocusedElementEffect';
import { RECORD_TABLE_CLICK_OUTSIDE_LISTENER_ID } from '@/object-record/record-table/constants/RecordTableClickOutsideListenerId';
import { useRecordTableContextOrThrow } from '@/object-record/record-table/contexts/RecordTableContext';
import { useRecordTable } from '@/object-record/record-table/hooks/useRecordTable';
import { isRecordTableFocusActiveComponentState } from '@/object-record/record-table/states/isRecordTableFocusActiveComponentState';
import { isRecordTableInitialLoadingComponentState } from '@/object-record/record-table/states/isRecordTableInitialLoadingComponentState';
import { useClickOutsideListener } from '@/ui/utilities/pointer-event/hooks/useClickOutsideListener';
import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2';
@ -44,6 +46,11 @@ export const RecordTable = () => {
const recordTableIsEmpty =
!isRecordTableInitialLoading && allRecordIds.length === 0;
const isRecordTableFocusActive = useRecoilComponentValueV2(
isRecordTableFocusActiveComponentState,
recordTableId,
);
if (!isNonEmptyString(objectNameSingular)) {
return <></>;
}
@ -64,6 +71,8 @@ export const RecordTable = () => {
tableBodyRef={tableBodyRef}
/>
{isRecordTableFocusActive && <RecordTableScrollToFocusedElementEffect />}
{recordTableIsEmpty && !hasRecordGroups ? (
<RecordTableEmpty
tableBodyRef={tableBodyRef}

View File

@ -1,10 +1,10 @@
import { RecordTableBodyEscapeHotkeyEffect } from '@/object-record/record-table/record-table-body/components/RecordTableBodyEscapeHotkeyEffect';
import { RecordTableBodySoftFocusClickOutsideEffect } from '@/object-record/record-table/record-table-body/components/RecordTableBodySoftFocusClickOutsideEffect';
import { RecordTableBodySoftFocusKeyboardEffect } from '@/object-record/record-table/record-table-body/components/RecordTableBodySoftFocusKeyboardEffect';
import { RecordTableBodyFocusClickOutsideEffect } from '@/object-record/record-table/record-table-body/components/RecordTableBodyFocusClickOutsideEffect';
import { RecordTableBodyFocusKeyboardEffect } from '@/object-record/record-table/record-table-body/components/RecordTableBodyFocusKeyboardEffect';
import { RecordTableNoRecordGroupBodyEffect } from '@/object-record/record-table/record-table-body/components/RecordTableNoRecordGroupBodyEffect';
import { RecordTableRecordGroupBodyEffects } from '@/object-record/record-table/record-table-body/components/RecordTableRecordGroupBodyEffects';
import { isAtLeastOneTableRowSelectedSelector } from '@/object-record/record-table/record-table-row/states/isAtLeastOneTableRowSelectedSelector';
import { isSoftFocusActiveComponentState } from '@/object-record/record-table/states/isSoftFocusActiveComponentState';
import { isRecordTableFocusActiveComponentState } from '@/object-record/record-table/states/isRecordTableFocusActiveComponentState';
import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2';
export interface RecordTableBodyEffectsWrapperProps {
@ -20,8 +20,8 @@ export const RecordTableBodyEffectsWrapper = ({
isAtLeastOneTableRowSelectedSelector,
);
const isSoftFocusActiveState = useRecoilComponentValueV2(
isSoftFocusActiveComponentState,
const isRecordTableFocusActive = useRecoilComponentValueV2(
isRecordTableFocusActiveComponentState,
);
return (
@ -32,11 +32,9 @@ export const RecordTableBodyEffectsWrapper = ({
<RecordTableNoRecordGroupBodyEffect />
)}
{isAtLeastOneRecordSelected && <RecordTableBodyEscapeHotkeyEffect />}
{isSoftFocusActiveState && <RecordTableBodySoftFocusKeyboardEffect />}
{isSoftFocusActiveState && (
<RecordTableBodySoftFocusClickOutsideEffect
tableBodyRef={tableBodyRef}
/>
{isRecordTableFocusActive && <RecordTableBodyFocusKeyboardEffect />}
{isRecordTableFocusActive && (
<RecordTableBodyFocusClickOutsideEffect tableBodyRef={tableBodyRef} />
)}
</>
);

View File

@ -1,5 +1,4 @@
import { useContext, useEffect, useRef } from 'react';
import { useRecoilValue } from 'recoil';
import { useContext } from 'react';
import { Key } from 'ts-key-enum';
import { useClearField } from '@/object-record/record-field/hooks/useClearField';
@ -7,17 +6,13 @@ import { useIsFieldClearable } from '@/object-record/record-field/hooks/useIsFie
import { useIsFieldInputOnly } from '@/object-record/record-field/hooks/useIsFieldInputOnly';
import { useToggleEditOnlyInput } from '@/object-record/record-field/hooks/useToggleEditOnlyInput';
import { useOpenRecordTableCellFromCell } from '@/object-record/record-table/record-table-cell/hooks/useOpenRecordTableCellFromCell';
import { isSoftFocusUsingMouseState } from '@/object-record/record-table/states/isSoftFocusUsingMouseState';
import { useScopedHotkeys } from '@/ui/utilities/hotkey/hooks/useScopedHotkeys';
import { isNonTextWritingKey } from '@/ui/utilities/hotkey/utils/isNonTextWritingKey';
import { FieldContext } from '@/object-record/record-field/contexts/FieldContext';
import { currentHotkeyScopeState } from '@/ui/utilities/hotkey/states/internal/currentHotkeyScopeState';
import { TableHotkeyScope } from '../../types/TableHotkeyScope';
export const RecordTableCellSoftFocusModeHotkeysSetterEffect = () => {
const currentHotkeyScope = useRecoilValue(currentHotkeyScopeState);
import { TableHotkeyScope } from '../types/TableHotkeyScope';
export const RecordTableFocusModeHotkeysSetterEffect = () => {
const { openTableCell } = useOpenRecordTableCellFromCell();
const { isReadOnly } = useContext(FieldContext);
@ -26,21 +21,9 @@ export const RecordTableCellSoftFocusModeHotkeysSetterEffect = () => {
const isFieldClearable = useIsFieldClearable();
const toggleEditOnlyInput = useToggleEditOnlyInput();
const scrollRef = useRef<HTMLDivElement>(null);
const isSoftFocusUsingMouse = useRecoilValue(isSoftFocusUsingMouseState);
const clearField = useClearField();
useEffect(() => {
if (currentHotkeyScope.scope !== TableHotkeyScope.TableSoftFocus) {
return;
}
if (!isSoftFocusUsingMouse) {
scrollRef.current?.scrollIntoView({ block: 'nearest' });
}
}, [currentHotkeyScope.scope, isSoftFocusUsingMouse]);
useScopedHotkeys(
[Key.Backspace, Key.Delete],
() => {
@ -48,7 +31,7 @@ export const RecordTableCellSoftFocusModeHotkeysSetterEffect = () => {
clearField();
}
},
TableHotkeyScope.TableSoftFocus,
TableHotkeyScope.TableFocus,
[clearField, isFieldClearable, isFieldInputOnly],
);
@ -65,8 +48,8 @@ export const RecordTableCellSoftFocusModeHotkeysSetterEffect = () => {
toggleEditOnlyInput();
}
},
TableHotkeyScope.TableSoftFocus,
[openTableCell],
TableHotkeyScope.TableFocus,
[openTableCell, isFieldInputOnly, toggleEditOnlyInput, isReadOnly],
);
useScopedHotkeys(
@ -93,8 +76,8 @@ export const RecordTableCellSoftFocusModeHotkeysSetterEffect = () => {
openTableCell(keyboardEvent.key);
}
},
TableHotkeyScope.TableSoftFocus,
[openTableCell],
TableHotkeyScope.TableFocus,
[openTableCell, isFieldInputOnly, toggleEditOnlyInput, isReadOnly],
{
preventDefault: false,
},

View File

@ -3,7 +3,7 @@ import { useRecordTableContextOrThrow } from '@/object-record/record-table/conte
import { useHandleContainerMouseEnter } from '@/object-record/record-table/hooks/internal/useHandleContainerMouseEnter';
import { useRecordTableMoveFocus } from '@/object-record/record-table/hooks/useRecordTableMoveFocus';
import { useCloseRecordTableCellNoGroup } from '@/object-record/record-table/record-table-cell/hooks/internal/useCloseRecordTableCellNoGroup';
import { useMoveSoftFocusToCurrentCellOnHover } from '@/object-record/record-table/record-table-cell/hooks/useMoveSoftFocusToCurrentCellOnHover';
import { useMoveHoverToCurrentCell } from '@/object-record/record-table/record-table-cell/hooks/useMoveHoverToCurrentCell';
import {
OpenTableCellArgs,
useOpenRecordTableCellV2,
@ -40,13 +40,10 @@ export const RecordTableNoRecordGroupBodyContextProvider = ({
closeTableCellNoGroup();
};
const { moveSoftFocusToCurrentCell } =
useMoveSoftFocusToCurrentCellOnHover(recordTableId);
const { moveHoverToCurrentCell } = useMoveHoverToCurrentCell(recordTableId);
const handleMoveSoftFocusToCurrentCell = (
cellPosition: TableCellPosition,
) => {
moveSoftFocusToCurrentCell(cellPosition);
const handleMoveHoverToCurrentCell = (cellPosition: TableCellPosition) => {
moveHoverToCurrentCell(cellPosition);
};
const { triggerActionMenuDropdown } = useTriggerActionMenuDropdown({
@ -70,7 +67,7 @@ export const RecordTableNoRecordGroupBodyContextProvider = ({
onOpenTableCell: handleOpenTableCell,
onMoveFocus: handleMoveFocus,
onCloseTableCell: handleCloseTableCell,
onMoveSoftFocusToCurrentCell: handleMoveSoftFocusToCurrentCell,
onMoveHoverToCurrentCell: handleMoveHoverToCurrentCell,
onActionMenuDropdownOpened: handleActionMenuDropdown,
onCellMouseEnter: handleContainerMouseEnter,
}}

View File

@ -3,7 +3,7 @@ import { useRecordTableContextOrThrow } from '@/object-record/record-table/conte
import { useHandleContainerMouseEnter } from '@/object-record/record-table/hooks/internal/useHandleContainerMouseEnter';
import { useRecordTableMoveFocus } from '@/object-record/record-table/hooks/useRecordTableMoveFocus';
import { useCloseRecordTableCellInGroup } from '@/object-record/record-table/record-table-cell/hooks/internal/useCloseRecordTableCellInGroup';
import { useMoveSoftFocusToCurrentCellOnHover } from '@/object-record/record-table/record-table-cell/hooks/useMoveSoftFocusToCurrentCellOnHover';
import { useMoveHoverToCurrentCell } from '@/object-record/record-table/record-table-cell/hooks/useMoveHoverToCurrentCell';
import {
OpenTableCellArgs,
useOpenRecordTableCellV2,
@ -41,13 +41,10 @@ export const RecordTableRecordGroupBodyContextProvider = ({
closeTableCellInGroup();
};
const { moveSoftFocusToCurrentCell } =
useMoveSoftFocusToCurrentCellOnHover(recordTableId);
const { moveHoverToCurrentCell } = useMoveHoverToCurrentCell(recordTableId);
const handleMoveSoftFocusToCurrentCell = (
cellPosition: TableCellPosition,
) => {
moveSoftFocusToCurrentCell(cellPosition);
const handleMoveHoverToCurrentCell = (cellPosition: TableCellPosition) => {
moveHoverToCurrentCell(cellPosition);
};
const { triggerActionMenuDropdown } = useTriggerActionMenuDropdown({
@ -71,7 +68,7 @@ export const RecordTableRecordGroupBodyContextProvider = ({
onOpenTableCell: handleOpenTableCell,
onMoveFocus: handleMoveFocus,
onCloseTableCell: handlecloseTableCellInGroup,
onMoveSoftFocusToCurrentCell: handleMoveSoftFocusToCurrentCell,
onMoveHoverToCurrentCell: handleMoveHoverToCurrentCell,
onActionMenuDropdownOpened: handleActionMenuDropdown,
onCellMouseEnter: handleContainerMouseEnter,
}}

View File

@ -0,0 +1,49 @@
import { recordTableFocusPositionComponentState } from '@/object-record/record-table/states/recordTableFocusPositionComponentState';
import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2';
import { useEffect } from 'react';
import { isDefined } from 'twenty-shared/utils';
export const RecordTableScrollToFocusedElementEffect = () => {
const focusPosition = useRecoilComponentValueV2(
recordTableFocusPositionComponentState,
);
useEffect(() => {
if (!focusPosition) {
return;
}
const focusElement = document.getElementById(
`record-table-cell-${focusPosition.column}-${focusPosition.row}`,
);
if (!focusElement) {
return;
}
const isSecondColumn = focusPosition.column === 1;
if (isSecondColumn) {
const checkBoxColumnCell = document.getElementById(
`record-table-cell-0-0`,
);
const firstColumnCell = document.getElementById(`record-table-cell-1-0`);
if (isDefined(checkBoxColumnCell) && isDefined(firstColumnCell)) {
const checkBoxColumnWidth = checkBoxColumnCell.offsetWidth;
const firstColumnWidth = firstColumnCell.offsetWidth;
focusElement.style.scrollMarginLeft = `${checkBoxColumnWidth + firstColumnWidth}px`;
}
}
focusElement.scrollIntoView({ behavior: 'smooth', block: 'nearest' });
return () => {
if (isDefined(focusElement)) {
focusElement.style.scrollMarginLeft = '';
}
};
}, [focusPosition]);
return null;
};

View File

@ -93,7 +93,7 @@ const meta: Meta = {
onOpenTableCell: () => {},
onMoveFocus: () => {},
onCloseTableCell: () => {},
onMoveSoftFocusToCurrentCell: () => {},
onMoveHoverToCurrentCell: () => {},
onActionMenuDropdownOpened: () => {},
onCellMouseEnter: () => {},
}}
@ -122,10 +122,7 @@ const meta: Meta = {
<RecordTableCellContext.Provider
value={{
columnDefinition: mockPerformance.fieldDefinition,
columnIndex: 0,
cellPosition: { row: 0, column: 0 },
hasSoftFocus: false,
isInEditMode: false,
}}
>
<FieldContext.Provider

View File

@ -0,0 +1,2 @@
export const FOCUS_CLICK_OUTSIDE_LISTENER_ID =
'focus-click-outside-listener-id';

View File

@ -1,2 +0,0 @@
export const SOFT_FOCUS_CLICK_OUTSIDE_LISTENER_ID =
'soft-focus-click-outside-listener-id';

View File

@ -11,7 +11,7 @@ export type RecordTableBodyContextProps = {
onOpenTableCell: (args: OpenTableCellArgs) => void;
onMoveFocus: (direction: MoveFocusDirection) => void;
onCloseTableCell: () => void;
onMoveSoftFocusToCurrentCell: (cellPosition: TableCellPosition) => void;
onMoveHoverToCurrentCell: (cellPosition: TableCellPosition) => void;
onActionMenuDropdownOpened: (
event: React.MouseEvent,
recordId: string,

View File

@ -6,9 +6,6 @@ import { TableCellPosition } from '@/object-record/record-table/types/TableCellP
export type RecordTableCellContextValue = {
columnDefinition: ColumnDefinition<FieldMetadata>;
columnIndex: number;
isInEditMode: boolean;
hasSoftFocus: boolean;
cellPosition: TableCellPosition;
};

View File

@ -1,45 +1,27 @@
import { useRecoilCallback } from 'recoil';
import { currentTableCellInEditModePositionComponentState } from '@/object-record/record-table/states/currentTableCellInEditModePositionComponentState';
import { isTableCellInEditModeComponentFamilyState } from '@/object-record/record-table/states/isTableCellInEditModeComponentFamilyState';
import { recordTableCellEditModePositionComponentState } from '@/object-record/record-table/states/recordTableCellEditModePositionComponentState';
import { useGoBackToPreviousDropdownFocusId } from '@/ui/layout/dropdown/hooks/useGoBackToPreviousDropdownFocusId';
import { getSnapshotValue } from '@/ui/utilities/recoil-scope/utils/getSnapshotValue';
import { useRecoilComponentCallbackStateV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentCallbackStateV2';
export const useCloseCurrentTableCellInEditMode = (recordTableId?: string) => {
const currentTableCellInEditModePositionState =
useRecoilComponentCallbackStateV2(
currentTableCellInEditModePositionComponentState,
recordTableCellEditModePositionComponentState,
recordTableId,
);
const isTableCellInEditModeFamilyState = useRecoilComponentCallbackStateV2(
isTableCellInEditModeComponentFamilyState,
recordTableId,
);
const { goBackToPreviousDropdownFocusId } =
useGoBackToPreviousDropdownFocusId();
return useRecoilCallback(
({ set, snapshot }) => {
({ set }) => {
return async () => {
const currentTableCellInEditModePosition = getSnapshotValue(
snapshot,
currentTableCellInEditModePositionState,
);
set(
isTableCellInEditModeFamilyState(currentTableCellInEditModePosition),
false,
);
set(currentTableCellInEditModePositionState, null);
goBackToPreviousDropdownFocusId();
};
},
[
currentTableCellInEditModePositionState,
isTableCellInEditModeFamilyState,
goBackToPreviousDropdownFocusId,
],
[currentTableCellInEditModePositionState, goBackToPreviousDropdownFocusId],
);
};

View File

@ -1,42 +0,0 @@
import { useRecoilCallback } from 'recoil';
import { isSoftFocusActiveComponentState } from '@/object-record/record-table/states/isSoftFocusActiveComponentState';
import { isSoftFocusOnTableCellComponentFamilyState } from '@/object-record/record-table/states/isSoftFocusOnTableCellComponentFamilyState';
import { softFocusPositionComponentState } from '@/object-record/record-table/states/softFocusPositionComponentState';
import { getSnapshotValue } from '@/ui/utilities/recoil-scope/utils/getSnapshotValue';
import { useRecoilComponentCallbackStateV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentCallbackStateV2';
export const useDisableSoftFocus = (recordTableId?: string) => {
const softFocusPositionState = useRecoilComponentCallbackStateV2(
softFocusPositionComponentState,
recordTableId,
);
const isSoftFocusActiveState = useRecoilComponentCallbackStateV2(
isSoftFocusActiveComponentState,
recordTableId,
);
const isSoftFocusOnTableCellFamilyState = useRecoilComponentCallbackStateV2(
isSoftFocusOnTableCellComponentFamilyState,
recordTableId,
);
return useRecoilCallback(
({ set, snapshot }) => {
return () => {
const currentPosition = getSnapshotValue(
snapshot,
softFocusPositionState,
);
set(isSoftFocusActiveState, false);
set(isSoftFocusOnTableCellFamilyState(currentPosition), false);
};
},
[
isSoftFocusActiveState,
softFocusPositionState,
isSoftFocusOnTableCellFamilyState,
],
);
};

View File

@ -1,35 +0,0 @@
import { useRecoilCallback } from 'recoil';
import { currentTableCellInEditModePositionComponentState } from '@/object-record/record-table/states/currentTableCellInEditModePositionComponentState';
import { isTableCellInEditModeComponentFamilyState } from '@/object-record/record-table/states/isTableCellInEditModeComponentFamilyState';
import { getSnapshotValue } from '@/ui/utilities/recoil-scope/utils/getSnapshotValue';
import { useRecoilComponentCallbackStateV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentCallbackStateV2';
export const useGetIsSomeCellInEditModeState = (recordTableId?: string) => {
const currentTableCellInEditModePositionState =
useRecoilComponentCallbackStateV2(
currentTableCellInEditModePositionComponentState,
recordTableId,
);
const isTableCellInEditModeFamilyState = useRecoilComponentCallbackStateV2(
isTableCellInEditModeComponentFamilyState,
recordTableId,
);
return useRecoilCallback(
({ snapshot }) =>
() => {
const currentTableCellInEditModePosition = getSnapshotValue(
snapshot,
currentTableCellInEditModePositionState,
);
const isSomeCellInEditModeState = isTableCellInEditModeFamilyState(
currentTableCellInEditModePosition,
);
return isSomeCellInEditModeState;
},
[currentTableCellInEditModePositionState, isTableCellInEditModeFamilyState],
);
};

View File

@ -1,10 +1,7 @@
import { useRecoilCallback } from 'recoil';
import { useMoveSoftFocusToCurrentCellOnHover } from '@/object-record/record-table/record-table-cell/hooks/useMoveSoftFocusToCurrentCellOnHover';
import { currentTableCellInEditModePositionComponentState } from '@/object-record/record-table/states/currentTableCellInEditModePositionComponentState';
import { isSoftFocusOnTableCellComponentFamilyState } from '@/object-record/record-table/states/isSoftFocusOnTableCellComponentFamilyState';
import { isSoftFocusUsingMouseState } from '@/object-record/record-table/states/isSoftFocusUsingMouseState';
import { isTableCellInEditModeComponentFamilyState } from '@/object-record/record-table/states/isTableCellInEditModeComponentFamilyState';
import { useMoveHoverToCurrentCell } from '@/object-record/record-table/record-table-cell/hooks/useMoveHoverToCurrentCell';
import { isSomeCellInEditModeComponentSelector } from '@/object-record/record-table/states/selectors/isSomeCellInEditModeComponentSelector';
import { TableCellPosition } from '@/object-record/record-table/types/TableCellPosition';
import { getSnapshotValue } from '@/ui/utilities/recoil-scope/utils/getSnapshotValue';
import { useRecoilComponentCallbackStateV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentCallbackStateV2';
@ -18,54 +15,26 @@ export const useHandleContainerMouseEnter = ({
}: {
recordTableId: string;
}) => {
const { moveSoftFocusToCurrentCell } =
useMoveSoftFocusToCurrentCellOnHover(recordTableId);
const { moveHoverToCurrentCell } = useMoveHoverToCurrentCell(recordTableId);
const currentTableCellInEditModePositionState =
useRecoilComponentCallbackStateV2(
currentTableCellInEditModePositionComponentState,
recordTableId,
);
const isSoftFocusOnTableCellFamilyState = useRecoilComponentCallbackStateV2(
isSoftFocusOnTableCellComponentFamilyState,
recordTableId,
);
const isTableCellInEditModeFamilyState = useRecoilComponentCallbackStateV2(
isTableCellInEditModeComponentFamilyState,
const isSomeCellInEditModeSelector = useRecoilComponentCallbackStateV2(
isSomeCellInEditModeComponentSelector,
recordTableId,
);
const handleContainerMouseEnter = useRecoilCallback(
({ snapshot, set }) =>
({ snapshot }) =>
({ cellPosition }: HandleContainerMouseEnterArgs) => {
const isSoftFocusOnTableCell = getSnapshotValue(
snapshot,
isSoftFocusOnTableCellFamilyState(cellPosition),
);
const currentTableCellInEditModePosition = getSnapshotValue(
snapshot,
currentTableCellInEditModePositionState,
);
const isSomeCellInEditMode = getSnapshotValue(
snapshot,
isTableCellInEditModeFamilyState(currentTableCellInEditModePosition),
isSomeCellInEditModeSelector,
);
if (!isSomeCellInEditMode && !isSoftFocusOnTableCell) {
moveSoftFocusToCurrentCell(cellPosition);
set(isSoftFocusUsingMouseState, true);
if (!isSomeCellInEditMode) {
moveHoverToCurrentCell(cellPosition);
}
},
[
isSoftFocusOnTableCellFamilyState,
currentTableCellInEditModePositionState,
isTableCellInEditModeFamilyState,
moveSoftFocusToCurrentCell,
],
[isSomeCellInEditModeSelector, moveHoverToCurrentCell],
);
return {

View File

@ -1,13 +1,7 @@
import { useRecoilCallback } from 'recoil';
import { getSnapshotValue } from '@/ui/utilities/recoil-scope/utils/getSnapshotValue';
import { useResetTableRowSelection } from '@/object-record/record-table/hooks/internal/useResetTableRowSelection';
import { useSetIsRecordTableFocusActive } from '@/object-record/record-table/record-table-cell/hooks/useSetIsRecordTableFocusActive';
import { RecordTableComponentInstanceContext } from '@/object-record/record-table/states/context/RecordTableComponentInstanceContext';
import { isSoftFocusActiveComponentState } from '@/object-record/record-table/states/isSoftFocusActiveComponentState';
import { useAvailableComponentInstanceIdOrThrow } from '@/ui/utilities/state/component-state/hooks/useAvailableComponentInstanceIdOrThrow';
import { useRecoilComponentCallbackStateV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentCallbackStateV2';
import { useDisableSoftFocus } from './useDisableSoftFocus';
export const useLeaveTableFocus = (recordTableId?: string) => {
const recordTableIdFromContext = useAvailableComponentInstanceIdOrThrow(
@ -15,33 +9,17 @@ export const useLeaveTableFocus = (recordTableId?: string) => {
recordTableId,
);
const disableSoftFocus = useDisableSoftFocus(recordTableIdFromContext);
const isSoftFocusActiveState = useRecoilComponentCallbackStateV2(
isSoftFocusActiveComponentState,
recordTableIdFromContext,
);
const resetTableRowSelection = useResetTableRowSelection(
recordTableIdFromContext,
);
return useRecoilCallback(
({ snapshot }) =>
() => {
const isSoftFocusActive = getSnapshotValue(
snapshot,
isSoftFocusActiveState,
);
resetTableRowSelection();
if (!isSoftFocusActive) {
return;
}
disableSoftFocus();
},
[disableSoftFocus, isSoftFocusActiveState, resetTableRowSelection],
const { setIsFocusActiveForCurrentPosition } = useSetIsRecordTableFocusActive(
recordTableIdFromContext,
);
return () => {
resetTableRowSelection();
setIsFocusActiveForCurrentPosition(false);
};
};

View File

@ -1,41 +0,0 @@
import { useRecoilCallback } from 'recoil';
import { getSnapshotValue } from '@/ui/utilities/recoil-scope/utils/getSnapshotValue';
import { currentTableCellInEditModePositionComponentState } from '@/object-record/record-table/states/currentTableCellInEditModePositionComponentState';
import { isTableCellInEditModeComponentFamilyState } from '@/object-record/record-table/states/isTableCellInEditModeComponentFamilyState';
import { useRecoilComponentCallbackStateV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentCallbackStateV2';
import { TableCellPosition } from '../../types/TableCellPosition';
export const useMoveEditModeToTableCellPosition = (recordTableId?: string) => {
const isTableCellInEditModeFamilyState = useRecoilComponentCallbackStateV2(
isTableCellInEditModeComponentFamilyState,
recordTableId,
);
const currentTableCellInEditModePositionState =
useRecoilComponentCallbackStateV2(
currentTableCellInEditModePositionComponentState,
recordTableId,
);
return useRecoilCallback(
({ set, snapshot }) => {
return (newPosition: TableCellPosition) => {
const currentTableCellInEditModePosition = getSnapshotValue(
snapshot,
currentTableCellInEditModePositionState,
);
set(
isTableCellInEditModeFamilyState(currentTableCellInEditModePosition),
false,
);
set(currentTableCellInEditModePositionState, newPosition);
set(isTableCellInEditModeFamilyState(newPosition), true);
};
},
[currentTableCellInEditModePositionState, isTableCellInEditModeFamilyState],
);
};

View File

@ -0,0 +1,28 @@
import { useRecoilCallback } from 'recoil';
import { recordTableFocusPositionComponentState } from '@/object-record/record-table/states/recordTableFocusPositionComponentState';
import { useRecoilComponentCallbackStateV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentCallbackStateV2';
import { useSetIsRecordTableFocusActive } from '../../record-table-cell/hooks/useSetIsRecordTableFocusActive';
import { TableCellPosition } from '../../types/TableCellPosition';
export const useSetRecordTableFocusPosition = (recordTableId?: string) => {
const focusPositionState = useRecoilComponentCallbackStateV2(
recordTableFocusPositionComponentState,
recordTableId,
);
const { setIsFocusActive, setIsFocusActiveForCurrentPosition } =
useSetIsRecordTableFocusActive(recordTableId);
return useRecoilCallback(
({ set }) => {
return (newPosition: TableCellPosition) => {
set(focusPositionState, newPosition);
setIsFocusActiveForCurrentPosition(false);
setIsFocusActive(true, newPosition);
};
},
[focusPositionState, setIsFocusActive, setIsFocusActiveForCurrentPosition],
);
};

View File

@ -1,48 +0,0 @@
import { useRecoilCallback } from 'recoil';
import { getSnapshotValue } from '@/ui/utilities/recoil-scope/utils/getSnapshotValue';
import { isSoftFocusActiveComponentState } from '@/object-record/record-table/states/isSoftFocusActiveComponentState';
import { isSoftFocusOnTableCellComponentFamilyState } from '@/object-record/record-table/states/isSoftFocusOnTableCellComponentFamilyState';
import { softFocusPositionComponentState } from '@/object-record/record-table/states/softFocusPositionComponentState';
import { useRecoilComponentCallbackStateV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentCallbackStateV2';
import { TableCellPosition } from '../../types/TableCellPosition';
export const useSetSoftFocusPosition = (recordTableId?: string) => {
const softFocusPositionState = useRecoilComponentCallbackStateV2(
softFocusPositionComponentState,
recordTableId,
);
const isSoftFocusActiveState = useRecoilComponentCallbackStateV2(
isSoftFocusActiveComponentState,
recordTableId,
);
const isSoftFocusOnTableCellFamilyState = useRecoilComponentCallbackStateV2(
isSoftFocusOnTableCellComponentFamilyState,
recordTableId,
);
return useRecoilCallback(
({ set, snapshot }) => {
return (newPosition: TableCellPosition) => {
const currentPosition = getSnapshotValue(
snapshot,
softFocusPositionState,
);
set(isSoftFocusActiveState, true);
set(isSoftFocusOnTableCellFamilyState(currentPosition), false);
set(softFocusPositionState, newPosition);
set(isSoftFocusOnTableCellFamilyState(newPosition), true);
};
},
[
softFocusPositionState,
isSoftFocusActiveState,
isSoftFocusOnTableCellFamilyState,
],
);
};

View File

@ -1,11 +1,9 @@
import { useRecoilCallback, useSetRecoilState } from 'recoil';
import { useRecoilCallback } from 'recoil';
import { Key } from 'ts-key-enum';
import { FieldMetadata } from '@/object-record/record-field/types/FieldMetadata';
import { useGetIsSomeCellInEditModeState } from '@/object-record/record-table/hooks/internal/useGetIsSomeCellInEditMode';
import { useSetHasUserSelectedAllRows } from '@/object-record/record-table/hooks/internal/useSetAllRowSelectedState';
import { useRecordTableMoveFocus } from '@/object-record/record-table/hooks/useRecordTableMoveFocus';
import { isSoftFocusUsingMouseState } from '@/object-record/record-table/states/isSoftFocusUsingMouseState';
import { useScopedHotkeys } from '@/ui/utilities/hotkey/hooks/useScopedHotkeys';
import { useSetHotkeyScope } from '@/ui/utilities/hotkey/hooks/useSetHotkeyScope';
import { getSnapshotValue } from '@/ui/utilities/recoil-scope/utils/getSnapshotValue';
@ -15,6 +13,7 @@ import { useUpsertRecordFromState } from '../../hooks/useUpsertRecordFromState';
import { ColumnDefinition } from '../types/ColumnDefinition';
import { TableHotkeyScope } from '../types/TableHotkeyScope';
import { useSetIsRecordTableFocusActive } from '@/object-record/record-table/record-table-cell/hooks/useSetIsRecordTableFocusActive';
import { availableTableColumnsComponentState } from '@/object-record/record-table/states/availableTableColumnsComponentState';
import { RecordTableComponentInstanceContext } from '@/object-record/record-table/states/context/RecordTableComponentInstanceContext';
import { isRecordTableInitialLoadingComponentState } from '@/object-record/record-table/states/isRecordTableInitialLoadingComponentState';
@ -26,13 +25,12 @@ import { tableLastRowVisibleComponentState } from '@/object-record/record-table/
import { useAvailableComponentInstanceIdOrThrow } from '@/ui/utilities/state/component-state/hooks/useAvailableComponentInstanceIdOrThrow';
import { useRecoilComponentCallbackStateV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentCallbackStateV2';
import { useSetRecoilComponentStateV2 } from '@/ui/utilities/state/component-state/hooks/useSetRecoilComponentStateV2';
import { useDisableSoftFocus } from './internal/useDisableSoftFocus';
import { useLeaveTableFocus } from './internal/useLeaveTableFocus';
import { useResetTableRowSelection } from './internal/useResetTableRowSelection';
import { useSelectAllRows } from './internal/useSelectAllRows';
import { useSetRecordTableData } from './internal/useSetRecordTableData';
import { useSetRecordTableFocusPosition } from './internal/useSetRecordTableFocusPosition';
import { useSetRowSelectedState } from './internal/useSetRowSelectedState';
import { useSetSoftFocusPosition } from './internal/useSetSoftFocusPosition';
type useRecordTableProps = {
recordTableId?: string;
@ -145,25 +143,23 @@ export const useRecordTable = (props?: useRecordTableProps) => {
const upsertRecordTableItem = useUpsertRecordFromState;
const setSoftFocusPosition = useSetSoftFocusPosition(recordTableId);
const setFocusPosition = useSetRecordTableFocusPosition(recordTableId);
const { setIsFocusActiveForCurrentPosition } =
useSetIsRecordTableFocusActive(recordTableId);
const { moveDown, moveLeft, moveRight, moveUp } =
useRecordTableMoveFocus(recordTableId);
const useMapKeyboardToSoftFocus = () => {
const disableSoftFocus = useDisableSoftFocus(recordTableId);
const useMapKeyboardToFocus = () => {
const setHotkeyScope = useSetHotkeyScope();
const setIsSoftFocusUsingMouseState = useSetRecoilState(
isSoftFocusUsingMouseState,
);
useScopedHotkeys(
[Key.ArrowUp, `${Key.Shift}+${Key.Enter}`],
() => {
moveUp();
},
TableHotkeyScope.TableSoftFocus,
TableHotkeyScope.TableFocus,
[moveUp],
);
@ -172,7 +168,7 @@ export const useRecordTable = (props?: useRecordTableProps) => {
() => {
moveDown();
},
TableHotkeyScope.TableSoftFocus,
TableHotkeyScope.TableFocus,
[moveDown],
);
@ -180,9 +176,8 @@ export const useRecordTable = (props?: useRecordTableProps) => {
[Key.ArrowLeft, `${Key.Shift}+${Key.Tab}`],
() => {
moveLeft();
setIsSoftFocusUsingMouseState(false);
},
TableHotkeyScope.TableSoftFocus,
TableHotkeyScope.TableFocus,
[moveLeft],
);
@ -190,9 +185,8 @@ export const useRecordTable = (props?: useRecordTableProps) => {
[Key.ArrowRight, Key.Tab],
() => {
moveRight();
setIsSoftFocusUsingMouseState(false);
},
TableHotkeyScope.TableSoftFocus,
TableHotkeyScope.TableFocus,
[moveRight],
);
@ -203,18 +197,15 @@ export const useRecordTable = (props?: useRecordTableProps) => {
goto: true,
keyboardShortcutMenu: true,
});
disableSoftFocus();
setIsFocusActiveForCurrentPosition(false);
},
TableHotkeyScope.TableSoftFocus,
[disableSoftFocus],
TableHotkeyScope.TableFocus,
[setIsFocusActiveForCurrentPosition],
);
};
const { selectAllRows } = useSelectAllRows(recordTableId);
const isSomeCellInEditModeState =
useGetIsSomeCellInEditModeState(recordTableId);
return {
onColumnsChange,
setAvailableTableColumns,
@ -228,13 +219,12 @@ export const useRecordTable = (props?: useRecordTableProps) => {
moveLeft,
moveRight,
moveUp,
useMapKeyboardToSoftFocus,
useMapKeyboardToFocus,
selectAllRows,
setOnColumnsChange,
setIsRecordTableInitialLoading,
setRecordTableLastRowVisible,
setSoftFocusPosition,
isSomeCellInEditModeState,
setFocusPosition,
setHasUserSelectedAllRows,
setOnToggleColumnFilter,
setOnToggleColumnSort,

View File

@ -4,16 +4,16 @@ import { MoveFocusDirection } from '@/object-record/record-table/types/MoveFocus
import { getSnapshotValue } from '@/ui/utilities/recoil-scope/utils/getSnapshotValue';
import { recordIndexAllRecordIdsComponentSelector } from '@/object-record/record-index/states/selectors/recordIndexAllRecordIdsComponentSelector';
import { useSetRecordTableFocusPosition } from '@/object-record/record-table/hooks/internal/useSetRecordTableFocusPosition';
import { recordTableFocusPositionComponentState } from '@/object-record/record-table/states/recordTableFocusPositionComponentState';
import { numberOfTableColumnsComponentSelector } from '@/object-record/record-table/states/selectors/numberOfTableColumnsComponentSelector';
import { softFocusPositionComponentState } from '@/object-record/record-table/states/softFocusPositionComponentState';
import { useRecoilComponentCallbackStateV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentCallbackStateV2';
import { useSetSoftFocusPosition } from './internal/useSetSoftFocusPosition';
export const useRecordTableMoveFocus = (recordTableId?: string) => {
const setSoftFocusPosition = useSetSoftFocusPosition(recordTableId);
const setFocusPosition = useSetRecordTableFocusPosition(recordTableId);
const softFocusPositionState = useRecoilComponentCallbackStateV2(
softFocusPositionComponentState,
const focusPositionState = useRecoilComponentCallbackStateV2(
recordTableFocusPositionComponentState,
recordTableId,
);
@ -25,23 +25,20 @@ export const useRecordTableMoveFocus = (recordTableId?: string) => {
const moveUp = useRecoilCallback(
({ snapshot }) =>
() => {
const softFocusPosition = getSnapshotValue(
snapshot,
softFocusPositionState,
);
const focusPosition = getSnapshotValue(snapshot, focusPositionState);
let newRowIndex = softFocusPosition.row - 1;
let newRowIndex = focusPosition.row - 1;
if (newRowIndex < 0) {
newRowIndex = 0;
}
setSoftFocusPosition({
...softFocusPosition,
setFocusPosition({
...focusPosition,
row: newRowIndex,
});
},
[softFocusPositionState, setSoftFocusPosition],
[focusPositionState, setFocusPosition],
);
const moveDown = useRecoilCallback(
@ -51,27 +48,20 @@ export const useRecordTableMoveFocus = (recordTableId?: string) => {
snapshot,
recordIndexAllRecordIdsSelector,
);
const softFocusPosition = getSnapshotValue(
snapshot,
softFocusPositionState,
);
const focusPosition = getSnapshotValue(snapshot, focusPositionState);
let newRowIndex = softFocusPosition.row + 1;
let newRowIndex = focusPosition.row + 1;
if (newRowIndex >= allRecordIds.length) {
newRowIndex = allRecordIds.length - 1;
}
setSoftFocusPosition({
...softFocusPosition,
setFocusPosition({
...focusPosition,
row: newRowIndex,
});
},
[
recordIndexAllRecordIdsSelector,
setSoftFocusPosition,
softFocusPositionState,
],
[recordIndexAllRecordIdsSelector, setFocusPosition, focusPositionState],
);
const numberOfTableColumnsSelector = useRecoilComponentCallbackStateV2(
@ -86,18 +76,15 @@ export const useRecordTableMoveFocus = (recordTableId?: string) => {
snapshot,
recordIndexAllRecordIdsSelector,
);
const softFocusPosition = getSnapshotValue(
snapshot,
softFocusPositionState,
);
const focusPosition = getSnapshotValue(snapshot, focusPositionState);
const numberOfTableColumns = getSnapshotValue(
snapshot,
numberOfTableColumnsSelector,
);
const currentColumnIndex = softFocusPosition.column;
const currentRowIndex = softFocusPosition.row;
const currentColumnIndex = focusPosition.column;
const currentRowIndex = focusPosition.row;
const isLastRowAndLastColumn =
currentColumnIndex === numberOfTableColumns - 1 &&
@ -114,12 +101,12 @@ export const useRecordTableMoveFocus = (recordTableId?: string) => {
}
if (isNotLastColumn) {
setSoftFocusPosition({
setFocusPosition({
row: currentRowIndex,
column: currentColumnIndex + 1,
});
} else if (isLastColumnButNotLastRow) {
setSoftFocusPosition({
setFocusPosition({
row: currentRowIndex + 1,
column: 0,
});
@ -127,27 +114,24 @@ export const useRecordTableMoveFocus = (recordTableId?: string) => {
},
[
recordIndexAllRecordIdsSelector,
softFocusPositionState,
focusPositionState,
numberOfTableColumnsSelector,
setSoftFocusPosition,
setFocusPosition,
],
);
const moveLeft = useRecoilCallback(
({ snapshot }) =>
() => {
const softFocusPosition = getSnapshotValue(
snapshot,
softFocusPositionState,
);
const focusPosition = getSnapshotValue(snapshot, focusPositionState);
const numberOfTableColumns = getSnapshotValue(
snapshot,
numberOfTableColumnsSelector,
);
const currentColumnIndex = softFocusPosition.column;
const currentRowIndex = softFocusPosition.row;
const currentColumnIndex = focusPosition.column;
const currentRowIndex = focusPosition.row;
const isFirstRowAndFirstColumn =
currentColumnIndex === 0 && currentRowIndex === 0;
@ -162,22 +146,18 @@ export const useRecordTableMoveFocus = (recordTableId?: string) => {
}
if (isNotFirstColumn) {
setSoftFocusPosition({
setFocusPosition({
row: currentRowIndex,
column: currentColumnIndex - 1,
});
} else if (isFirstColumnButNotFirstRow) {
setSoftFocusPosition({
setFocusPosition({
row: currentRowIndex - 1,
column: numberOfTableColumns - 1,
});
}
},
[
numberOfTableColumnsSelector,
softFocusPositionState,
setSoftFocusPosition,
],
[numberOfTableColumnsSelector, focusPositionState, setFocusPosition],
);
const moveFocus = (direction: MoveFocusDirection) => {
@ -202,7 +182,7 @@ export const useRecordTableMoveFocus = (recordTableId?: string) => {
moveLeft,
moveRight,
moveUp,
setSoftFocusPosition,
setFocusPosition,
moveFocus,
};
};

View File

@ -3,13 +3,13 @@ import { useRecordTableContextOrThrow } from '@/object-record/record-table/conte
import { useLeaveTableFocus } from '@/object-record/record-table/hooks/internal/useLeaveTableFocus';
import { useListenClickOutside } from '@/ui/utilities/pointer-event/hooks/useListenClickOutside';
type RecordTableBodySoftFocusClickOutsideEffectProps = {
type RecordTableBodyFocusClickOutsideEffectProps = {
tableBodyRef: React.RefObject<HTMLDivElement>;
};
export const RecordTableBodySoftFocusClickOutsideEffect = ({
export const RecordTableBodyFocusClickOutsideEffect = ({
tableBodyRef,
}: RecordTableBodySoftFocusClickOutsideEffectProps) => {
}: RecordTableBodyFocusClickOutsideEffectProps) => {
const { recordTableId } = useRecordTableContextOrThrow();
const leaveTableFocus = useLeaveTableFocus(recordTableId);

View File

@ -1,14 +1,14 @@
import { useRecordTableContextOrThrow } from '@/object-record/record-table/contexts/RecordTableContext';
import { useRecordTable } from '@/object-record/record-table/hooks/useRecordTable';
export const RecordTableBodySoftFocusKeyboardEffect = () => {
export const RecordTableBodyFocusKeyboardEffect = () => {
const { recordTableId } = useRecordTableContextOrThrow();
const { useMapKeyboardToSoftFocus } = useRecordTable({
const { useMapKeyboardToFocus } = useRecordTable({
recordTableId,
});
useMapKeyboardToSoftFocus();
useMapKeyboardToFocus();
return <></>;
};

View File

@ -4,6 +4,7 @@ import { RecordTableNoRecordGroupRows } from '@/object-record/record-table/compo
import { RecordTableBodyDragDropContextProvider } from '@/object-record/record-table/record-table-body/components/RecordTableBodyDragDropContextProvider';
import { RecordTableBodyDroppable } from '@/object-record/record-table/record-table-body/components/RecordTableBodyDroppable';
import { RecordTableBodyLoading } from '@/object-record/record-table/record-table-body/components/RecordTableBodyLoading';
import { RecordTableCellPortals } from '@/object-record/record-table/record-table-cell/components/RecordTableCellPortals';
import { isRecordTableInitialLoadingComponentState } from '@/object-record/record-table/states/isRecordTableInitialLoadingComponentState';
import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2';
@ -25,6 +26,7 @@ export const RecordTableNoRecordGroupBody = () => {
<RecordTableBodyDragDropContextProvider>
<RecordTableBodyDroppable>
<RecordTableNoRecordGroupRows />
<RecordTableCellPortals />
</RecordTableBodyDroppable>
</RecordTableBodyDragDropContextProvider>
</RecordTableNoRecordGroupBodyContextProvider>

View File

@ -6,6 +6,7 @@ import { RecordTableRecordGroupRows } from '@/object-record/record-table/compone
import { RecordTableBodyDroppable } from '@/object-record/record-table/record-table-body/components/RecordTableBodyDroppable';
import { RecordTableBodyLoading } from '@/object-record/record-table/record-table-body/components/RecordTableBodyLoading';
import { RecordTableBodyRecordGroupDragDropContextProvider } from '@/object-record/record-table/record-table-body/components/RecordTableBodyRecordGroupDragDropContextProvider';
import { RecordTableCellPortals } from '@/object-record/record-table/record-table-cell/components/RecordTableCellPortals';
import { RecordTableRecordGroupSection } from '@/object-record/record-table/record-table-section/components/RecordTableRecordGroupSection';
import { isRecordTableInitialLoadingComponentState } from '@/object-record/record-table/states/isRecordTableInitialLoadingComponentState';
import { useRecoilComponentFamilyValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentFamilyValueV2';
@ -42,6 +43,7 @@ export const RecordTableRecordGroupsBody = () => {
<RecordTableBodyDroppable recordGroupId={recordGroupId}>
<RecordTableRecordGroupSection />
<RecordTableRecordGroupRows />
<RecordTableCellPortals />
</RecordTableBodyDroppable>
</RecordGroupContext.Provider>
</RecordTableRecordGroupBodyContextProvider>

View File

@ -1,15 +1,11 @@
import { FieldDisplay } from '@/object-record/record-field/components/FieldDisplay';
import { FieldFocusContextProvider } from '@/object-record/record-field/contexts/FieldFocusContextProvider';
import { RecordTableCellContainer } from '@/object-record/record-table/record-table-cell/components/RecordTableCellContainer';
import { RecordTableCellFieldInput } from '@/object-record/record-table/record-table-cell/components/RecordTableCellFieldInput';
export const RecordTableCell = () => {
return (
<FieldFocusContextProvider>
<RecordTableCellContainer
editModeContent={<RecordTableCellFieldInput />}
nonEditModeContent={<FieldDisplay />}
/>
<RecordTableCellContainer nonEditModeContent={<FieldDisplay />} />
</FieldFocusContextProvider>
);
};

View File

@ -9,11 +9,11 @@ import { useOpenRecordTableCellFromCell } from '@/object-record/record-table/rec
import { BORDER_COMMON, ThemeContext } from 'twenty-ui/theme';
const StyledBaseContainer = styled.div<{
hasSoftFocus: boolean;
fontColorExtraLight: string;
fontColorMedium: string;
backgroundColorTransparentSecondary: string;
isReadOnly: boolean;
borderColorBlue: string;
}>`
align-items: center;
box-sizing: border-box;
@ -23,23 +23,10 @@ const StyledBaseContainer = styled.div<{
position: relative;
user-select: none;
background: ${({ hasSoftFocus, backgroundColorTransparentSecondary }) =>
hasSoftFocus ? backgroundColorTransparentSecondary : 'none'};
border-radius: ${({ hasSoftFocus, isReadOnly }) =>
hasSoftFocus && !isReadOnly ? BORDER_COMMON.radius.sm : 'none'};
outline: ${({
hasSoftFocus,
fontColorExtraLight,
fontColorMedium,
isReadOnly,
}) =>
hasSoftFocus
? isReadOnly
? `1px solid ${fontColorMedium}`
: `1px solid ${fontColorExtraLight}`
: 'none'};
&.focus-active {
border-radius: ${BORDER_COMMON.radius.sm};
outline: 1px solid ${({ borderColorBlue }) => borderColorBlue};
}
`;
export const RecordTableCellBaseContainer = ({
@ -52,18 +39,16 @@ export const RecordTableCellBaseContainer = ({
const { openTableCell } = useOpenRecordTableCellFromCell();
const { theme } = useContext(ThemeContext);
const { hasSoftFocus, cellPosition } = useContext(RecordTableCellContext);
const { cellPosition } = useContext(RecordTableCellContext);
const { onMoveSoftFocusToCurrentCell, onCellMouseEnter } =
const { onMoveHoverToCurrentCell, onCellMouseEnter } =
useRecordTableBodyContextOrThrow();
const handleContainerMouseMove = () => {
setIsFocused(true);
if (!hasSoftFocus) {
onCellMouseEnter({
cellPosition,
});
}
onCellMouseEnter({
cellPosition,
});
};
const handleContainerMouseLeave = () => {
@ -71,10 +56,8 @@ export const RecordTableCellBaseContainer = ({
};
const handleContainerClick = () => {
if (!hasSoftFocus) {
onMoveSoftFocusToCurrentCell(cellPosition);
openTableCell();
}
onMoveHoverToCurrentCell(cellPosition);
openTableCell();
};
return (
@ -87,8 +70,9 @@ export const RecordTableCellBaseContainer = ({
}
fontColorExtraLight={theme.font.color.extraLight}
fontColorMedium={theme.border.color.medium}
hasSoftFocus={hasSoftFocus}
borderColorBlue={theme.adaptiveColors.blue4}
isReadOnly={isReadOnly ?? false}
id={`record-table-cell-${cellPosition.column}-${cellPosition.row}`}
>
{children}
</StyledBaseContainer>

View File

@ -1,14 +1,10 @@
import { ReactElement, useContext } from 'react';
import { ReactElement } from 'react';
import { RecordTableCellContext } from '@/object-record/record-table/contexts/RecordTableCellContext';
import { RecordTableCellBaseContainer } from '@/object-record/record-table/record-table-cell/components/RecordTableCellBaseContainer';
import { RecordTableCellSoftFocusModeHotkeysSetterEffect } from '@/object-record/record-table/record-table-cell/components/RecordTableCellSoftFocusModeHotkeysSetterEffect';
import { RecordTableCellDisplayMode } from './RecordTableCellDisplayMode';
import { RecordTableCellEditMode } from './RecordTableCellEditMode';
export type RecordTableCellContainerProps = {
editModeContent: ReactElement;
nonEditModeContent: ReactElement;
transparent?: boolean;
maxContentWidth?: number;
@ -17,23 +13,13 @@ export type RecordTableCellContainerProps = {
};
export const RecordTableCellContainer = ({
editModeContent,
nonEditModeContent,
}: RecordTableCellContainerProps) => {
const { hasSoftFocus, isInEditMode } = useContext(RecordTableCellContext);
return (
<RecordTableCellBaseContainer>
{isInEditMode ? (
<RecordTableCellEditMode>{editModeContent}</RecordTableCellEditMode>
) : (
<RecordTableCellDisplayMode>
{nonEditModeContent}
</RecordTableCellDisplayMode>
)}
{hasSoftFocus ? (
<RecordTableCellSoftFocusModeHotkeysSetterEffect />
) : null}
<RecordTableCellDisplayMode>
{nonEditModeContent}
</RecordTableCellDisplayMode>
</RecordTableCellBaseContainer>
);
};

View File

@ -26,7 +26,7 @@ const StyledEmptyPlaceholderField = withTheme(styled.div<{ theme: Theme }>`
`);
export type EditableCellDisplayContainerProps = {
softFocus?: boolean;
focus?: boolean;
onClick?: () => void;
scrollRef?: Ref<HTMLDivElement>;
isHovered?: boolean;
@ -36,7 +36,7 @@ export type EditableCellDisplayContainerProps = {
export const RecordTableCellDisplayContainer = ({
children,
softFocus,
focus,
onClick,
scrollRef,
onContextMenu,
@ -44,7 +44,7 @@ export const RecordTableCellDisplayContainer = ({
}: React.PropsWithChildren<EditableCellDisplayContainerProps>) => (
<StyledOuterContainer
data-testid={
softFocus ? 'editable-cell-soft-focus-mode' : 'editable-cell-display-mode'
focus ? 'editable-cell-focus-mode' : 'editable-cell-display-mode'
}
onClick={onClick}
ref={scrollRef}

View File

@ -1,34 +1,22 @@
import { FieldContext } from '@/object-record/record-field/contexts/FieldContext';
import { useIsFieldInputOnly } from '@/object-record/record-field/hooks/useIsFieldInputOnly';
import { useRecordTableBodyContextOrThrow } from '@/object-record/record-table/contexts/RecordTableBodyContext';
import { RecordTableCellContext } from '@/object-record/record-table/contexts/RecordTableCellContext';
import { RecordTableCellEditButton } from '@/object-record/record-table/record-table-cell/components/RecordTableCellEditButton';
import { useOpenRecordTableCellFromCell } from '@/object-record/record-table/record-table-cell/hooks/useOpenRecordTableCellFromCell';
import { useIsMobile } from '@/ui/utilities/responsive/hooks/useIsMobile';
import { useContext } from 'react';
import { ReactNode, useContext } from 'react';
import { RecordTableCellDisplayContainer } from './RecordTableCellDisplayContainer';
export const RecordTableCellDisplayMode = ({
children,
}: React.PropsWithChildren) => {
}: {
children: ReactNode;
}) => {
const { recordId, isReadOnly } = useContext(FieldContext);
const { columnIndex, hasSoftFocus } = useContext(RecordTableCellContext);
const isMobile = useIsMobile();
const { onActionMenuDropdownOpened } = useRecordTableBodyContextOrThrow();
const { openTableCell } = useOpenRecordTableCellFromCell();
const isFieldInputOnly = useIsFieldInputOnly();
const isFirstColumn = columnIndex === 0;
const showButton =
hasSoftFocus &&
!isFieldInputOnly &&
!isReadOnly &&
!(isMobile && isFirstColumn);
const handleActionMenuDropdown = (event: React.MouseEvent) => {
onActionMenuDropdownOpened(event, recordId);
@ -41,15 +29,11 @@ export const RecordTableCellDisplayMode = ({
};
return (
<>
<RecordTableCellDisplayContainer
softFocus={hasSoftFocus}
onContextMenu={handleActionMenuDropdown}
onClick={handleClick}
>
{children}
</RecordTableCellDisplayContainer>
{showButton && <RecordTableCellEditButton />}
</>
<RecordTableCellDisplayContainer
onContextMenu={handleActionMenuDropdown}
onClick={handleClick}
>
{children}
</RecordTableCellDisplayContainer>
);
};

View File

@ -8,12 +8,12 @@ import { isDefined } from 'twenty-shared/utils';
import { IconArrowUpRight, IconPencil } from 'twenty-ui/display';
export const RecordTableCellEditButton = () => {
const { columnIndex } = useContext(RecordTableCellContext);
const { cellPosition } = useContext(RecordTableCellContext);
const { openTableCell } = useOpenRecordTableCellFromCell();
const isFieldInputOnly = useIsFieldInputOnly();
const isFirstColumn = columnIndex === 0;
const isFirstColumn = cellPosition.column === 0;
const customButtonIcon = useGetButtonIcon();
const buttonIcon = isFirstColumn

View File

@ -1,7 +1,10 @@
import { useIsFieldInputOnly } from '@/object-record/record-field/hooks/useIsFieldInputOnly';
import { RecordFieldComponentInstanceContext } from '@/object-record/record-field/states/contexts/RecordFieldComponentInstanceContext';
import { recordFieldInputIsFieldInErrorComponentState } from '@/object-record/record-field/states/recordFieldInputIsFieldInErrorComponentState';
import { recordFieldInputLayoutDirectionComponentState } from '@/object-record/record-field/states/recordFieldInputLayoutDirectionComponentState';
import { recordFieldInputLayoutDirectionLoadingComponentState } from '@/object-record/record-field/states/recordFieldInputLayoutDirectionLoadingComponentState';
import { RecordTableCellContext } from '@/object-record/record-table/contexts/RecordTableCellContext';
import { useSetRecordTableFocusPosition } from '@/object-record/record-table/hooks/internal/useSetRecordTableFocusPosition';
import { OverlayContainer } from '@/ui/layout/overlay/components/OverlayContainer';
import { useAvailableComponentInstanceIdOrThrow } from '@/ui/utilities/state/component-state/hooks/useAvailableComponentInstanceIdOrThrow';
import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2';
@ -14,9 +17,11 @@ import {
offset,
useFloating,
} from '@floating-ui/react';
import { ReactElement } from 'react';
import { ReactElement, useContext } from 'react';
const StyledEditableCellEditModeContainer = styled.div<RecordTableCellEditModeProps>`
const StyledEditableCellEditModeContainer = styled.div<{
isFieldInputOnly: boolean;
}>`
align-items: center;
display: flex;
height: 100%;
@ -25,11 +30,17 @@ const StyledEditableCellEditModeContainer = styled.div<RecordTableCellEditModePr
z-index: 6;
`;
const StyledInputModeOnlyContainer = styled.div`
align-items: center;
display: flex;
height: 100%;
overflow: hidden;
padding-left: 8px;
width: 100%;
`;
export type RecordTableCellEditModeProps = {
children: ReactElement;
transparent?: boolean;
maxContentWidth?: number;
initialValue?: string;
};
export const RecordTableCellEditMode = ({
@ -77,19 +88,36 @@ export const RecordTableCellEditMode = ({
whileElementsMounted: autoUpdate,
});
const isFieldInputOnly = useIsFieldInputOnly();
const { cellPosition } = useContext(RecordTableCellContext);
const setFocusPosition = useSetRecordTableFocusPosition();
return (
<StyledEditableCellEditModeContainer
ref={refs.setReference}
data-testid="editable-cell-edit-mode-container"
isFieldInputOnly={isFieldInputOnly}
>
<OverlayContainer
ref={refs.setFloating}
style={floatingStyles}
borderRadius="sm"
hasDangerBorder={isFieldInError}
>
{children}
</OverlayContainer>
{isFieldInputOnly ? (
<StyledInputModeOnlyContainer
onClick={() => {
setFocusPosition(cellPosition);
}}
>
{children}
</StyledInputModeOnlyContainer>
) : (
<OverlayContainer
ref={refs.setFloating}
style={floatingStyles}
borderRadius="sm"
hasDangerBorder={isFieldInError}
>
{children}
</OverlayContainer>
)}
</StyledEditableCellEditModeContainer>
);
};

View File

@ -0,0 +1,44 @@
import { RecordTableCellPortalWrapper } from '@/object-record/record-table/record-table-cell/components/RecordTableCellPortalWrapper';
import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2';
import { RecordTableFocusModeHotkeysSetterEffect } from '@/object-record/record-table/components/RecordTableFocusModeHotkeysSetterEffect';
import { RecordTableCellEditMode } from '@/object-record/record-table/record-table-cell/components/RecordTableCellEditMode';
import { RecordTableCellFieldInput } from '@/object-record/record-table/record-table-cell/components/RecordTableCellFieldInput';
import { recordTableCellEditModePositionComponentState } from '@/object-record/record-table/states/recordTableCellEditModePositionComponentState';
import { recordTableFocusPositionComponentState } from '@/object-record/record-table/states/recordTableFocusPositionComponentState';
import styled from '@emotion/styled';
const StyledRecordTableCellHoveredPortal = styled.div`
height: 100%;
left: 0;
position: absolute;
top: 0;
width: 100%;
`;
export const RecordTableCellEditModePortal = () => {
const focusedCellPosition = useRecoilComponentValueV2(
recordTableFocusPositionComponentState,
);
const currentTableCellInEditModePosition = useRecoilComponentValueV2(
recordTableCellEditModePositionComponentState,
);
if (!focusedCellPosition) {
return null;
}
return (
<RecordTableCellPortalWrapper position={focusedCellPosition}>
{currentTableCellInEditModePosition && (
<StyledRecordTableCellHoveredPortal>
<RecordTableCellEditMode>
<RecordTableCellFieldInput />
</RecordTableCellEditMode>
</StyledRecordTableCellHoveredPortal>
)}
<RecordTableFocusModeHotkeysSetterEffect />
</RecordTableCellPortalWrapper>
);
};

View File

@ -0,0 +1,96 @@
import { RecordTableCellPortalWrapper } from '@/object-record/record-table/record-table-cell/components/RecordTableCellPortalWrapper';
import { recordTableHoverPositionComponentState } from '@/object-record/record-table/states/recordTableHoverPositionComponentState';
import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2';
import styled from '@emotion/styled';
import { FieldDisplay } from '@/object-record/record-field/components/FieldDisplay';
import { FieldContext } from '@/object-record/record-field/contexts/FieldContext';
import { useIsFieldInputOnly } from '@/object-record/record-field/hooks/useIsFieldInputOnly';
import { RecordTableCellDisplayMode } from '@/object-record/record-table/record-table-cell/components/RecordTableCellDisplayMode';
import { RecordTableCellEditButton } from '@/object-record/record-table/record-table-cell/components/RecordTableCellEditButton';
import { RecordTableCellEditMode } from '@/object-record/record-table/record-table-cell/components/RecordTableCellEditMode';
import { RecordTableCellFieldInput } from '@/object-record/record-table/record-table-cell/components/RecordTableCellFieldInput';
import { useContext } from 'react';
import { BORDER_COMMON } from 'twenty-ui/theme';
import { useIsMobile } from 'twenty-ui/utilities';
const StyledRecordTableCellHoveredPortalContent = styled.div<{
isReadOnly: boolean;
}>`
align-items: center;
background: ${({ theme }) => theme.background.transparent.secondary};
background-color: ${({ theme }) => theme.background.primary};
border-radius: ${({ isReadOnly }) =>
!isReadOnly ? BORDER_COMMON.radius.sm : 'none'};
box-sizing: border-box;
cursor: ${({ isReadOnly }) => (isReadOnly ? 'default' : 'pointer')};
display: flex;
height: 32px;
outline: ${({ theme, isReadOnly }) =>
isReadOnly
? `1px solid ${theme.border.color.medium}`
: `1px solid ${theme.font.color.extraLight}`};
position: relative;
user-select: none;
`;
const RecordTableCellHoveredPortalContent = () => {
const hoverPosition = useRecoilComponentValueV2(
recordTableHoverPositionComponentState,
);
const isMobile = useIsMobile();
const isFirstColumn = hoverPosition?.column === 0;
const { isReadOnly } = useContext(FieldContext);
const isFieldInputOnly = useIsFieldInputOnly();
const showButton =
!isFieldInputOnly && !isReadOnly && !(isMobile && isFirstColumn);
return (
<StyledRecordTableCellHoveredPortalContent isReadOnly={isReadOnly}>
{isFieldInputOnly ? (
<RecordTableCellEditMode>
<RecordTableCellFieldInput />
</RecordTableCellEditMode>
) : (
<RecordTableCellDisplayMode>
<FieldDisplay />
</RecordTableCellDisplayMode>
)}
{showButton && <RecordTableCellEditButton />}
</StyledRecordTableCellHoveredPortalContent>
);
};
const StyledRecordTableCellHoveredPortal = styled.div`
height: 100%;
left: 0;
position: absolute;
top: 0;
width: 100%;
`;
export const RecordTableCellHoveredPortal = () => {
const hoverPosition = useRecoilComponentValueV2(
recordTableHoverPositionComponentState,
);
if (!hoverPosition) {
return null;
}
return (
<RecordTableCellPortalWrapper position={hoverPosition}>
<StyledRecordTableCellHoveredPortal>
<RecordTableCellHoveredPortalContent />
</StyledRecordTableCellHoveredPortal>
</RecordTableCellPortalWrapper>
);
};

View File

@ -0,0 +1,66 @@
import { useContextStoreObjectMetadataItemOrThrow } from '@/context-store/hooks/useContextStoreObjectMetadataItemOrThrow';
import { getBasePathToShowPage } from '@/object-metadata/utils/getBasePathToShowPage';
import { recordIndexAllRecordIdsComponentSelector } from '@/object-record/record-index/states/selectors/recordIndexAllRecordIdsComponentSelector';
import { RecordTableCellContext } from '@/object-record/record-table/contexts/RecordTableCellContext';
import { RecordTableRowContextProvider } from '@/object-record/record-table/contexts/RecordTableRowContext';
import { RecordTableCellFieldContextWrapper } from '@/object-record/record-table/record-table-cell/components/RecordTableCellFieldContextWrapper';
import { visibleTableColumnsComponentSelector } from '@/object-record/record-table/states/selectors/visibleTableColumnsComponentSelector';
import { TableCellPosition } from '@/object-record/record-table/types/TableCellPosition';
import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2';
import ReactDOM from 'react-dom';
export const RecordTableCellPortalWrapper = ({
position,
children,
}: {
position: TableCellPosition;
children: React.ReactNode;
}) => {
const anchorElement = document.body.querySelector(
`#record-table-cell-${position.column}-${position.row}`,
) as HTMLElement;
const allRecordIds = useRecoilComponentValueV2(
recordIndexAllRecordIdsComponentSelector,
);
const { objectMetadataItem } = useContextStoreObjectMetadataItemOrThrow();
const visibleTableColumns = useRecoilComponentValueV2(
visibleTableColumnsComponentSelector,
);
if (!anchorElement) {
return null;
}
const recordId = allRecordIds[position.row];
return ReactDOM.createPortal(
<RecordTableRowContextProvider
value={{
recordId,
rowIndex: position.row,
isSelected: false,
inView: true,
pathToShowPage:
getBasePathToShowPage({
objectNameSingular: objectMetadataItem.nameSingular,
}) + recordId,
objectNameSingular: objectMetadataItem.nameSingular,
}}
>
<RecordTableCellContext.Provider
value={{
columnDefinition: visibleTableColumns[position.column],
cellPosition: position,
}}
>
<RecordTableCellFieldContextWrapper>
{children}
</RecordTableCellFieldContextWrapper>
</RecordTableCellContext.Provider>
</RecordTableRowContextProvider>,
anchorElement,
);
};

View File

@ -0,0 +1,22 @@
import { useRecordTableContextOrThrow } from '@/object-record/record-table/contexts/RecordTableContext';
import { RecordTableCellEditModePortal } from '@/object-record/record-table/record-table-cell/components/RecordTableCellEditModePortal';
import { RecordTableCellHoveredPortal } from '@/object-record/record-table/record-table-cell/components/RecordTableCellHoveredPortal';
import { isRecordTableFocusActiveComponentState } from '@/object-record/record-table/states/isRecordTableFocusActiveComponentState';
import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2';
export const RecordTableCellPortals = () => {
const { recordTableId } = useRecordTableContextOrThrow();
const isRecordTableFocusActive = useRecoilComponentValueV2(
isRecordTableFocusActiveComponentState,
recordTableId,
);
return (
<>
<RecordTableCellHoveredPortal />
{isRecordTableFocusActive && <RecordTableCellEditModePortal />}
</>
);
};

View File

@ -2,11 +2,8 @@ import { FieldMetadata } from '@/object-record/record-field/types/FieldMetadata'
import { RecordTableCellContext } from '@/object-record/record-table/contexts/RecordTableCellContext';
import { useRecordTableRowContextOrThrow } from '@/object-record/record-table/contexts/RecordTableRowContext';
import { RecordTableCellFieldContextWrapper } from '@/object-record/record-table/record-table-cell/components/RecordTableCellFieldContextWrapper';
import { isSoftFocusOnTableCellComponentFamilyState } from '@/object-record/record-table/states/isSoftFocusOnTableCellComponentFamilyState';
import { isTableCellInEditModeComponentFamilyState } from '@/object-record/record-table/states/isTableCellInEditModeComponentFamilyState';
import { ColumnDefinition } from '@/object-record/record-table/types/ColumnDefinition';
import { TableCellPosition } from '@/object-record/record-table/types/TableCellPosition';
import { useRecoilComponentFamilyValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentFamilyValueV2';
import { useMemo } from 'react';
export const RecordTableCellWrapper = ({
@ -28,23 +25,10 @@ export const RecordTableCellWrapper = ({
[columnIndex, rowIndex],
);
const isInEditMode = useRecoilComponentFamilyValueV2(
isTableCellInEditModeComponentFamilyState,
currentTableCellPosition,
);
const hasSoftFocus = useRecoilComponentFamilyValueV2(
isSoftFocusOnTableCellComponentFamilyState,
currentTableCellPosition,
);
return (
<RecordTableCellContext.Provider
value={{
columnDefinition: column,
columnIndex,
isInEditMode,
hasSoftFocus,
cellPosition: currentTableCellPosition,
}}
key={column.fieldMetadataId}

View File

@ -18,7 +18,6 @@ export const recordTableRowDraggableContextValue: RecordTableRowDraggableContext
};
export const recordTableCellContextValue: RecordTableCellContextValue = {
columnIndex: 3,
columnDefinition: {
size: 1,
position: 1,
@ -35,6 +34,4 @@ export const recordTableCellContextValue: RecordTableCellContextValue = {
row: 2,
column: 3,
},
hasSoftFocus: false,
isInEditMode: false,
};

View File

@ -1,37 +0,0 @@
import { renderHook } from '@testing-library/react';
import { RecordTableCellContext } from '@/object-record/record-table/contexts/RecordTableCellContext';
import { RecordTableRowContextProvider } from '@/object-record/record-table/contexts/RecordTableRowContext';
import { RecordTableRowDraggableContextProvider } from '@/object-record/record-table/contexts/RecordTableRowDraggableContext';
import {
recordTableCellContextValue,
recordTableRowContextValue,
recordTableRowDraggableContextValue,
} from '@/object-record/record-table/record-table-cell/hooks/__mocks__/cell';
import { useCurrentTableCellPosition } from '../useCurrentCellPosition';
describe('useCurrentTableCellPosition', () => {
it('should return the current table cell position', () => {
const wrapper = ({ children }: { children: React.ReactNode }) => (
<RecordTableRowContextProvider value={recordTableRowContextValue}>
<RecordTableRowDraggableContextProvider
value={recordTableRowDraggableContextValue}
>
<RecordTableCellContext.Provider value={recordTableCellContextValue}>
{children}
</RecordTableCellContext.Provider>
</RecordTableRowDraggableContextProvider>
</RecordTableRowContextProvider>
);
const { result } = renderHook(() => useCurrentTableCellPosition(), {
wrapper,
});
expect(result.current).toEqual({
column: 3,
row: 2,
});
});
});

View File

@ -1,50 +0,0 @@
import { act, renderHook, waitFor } from '@testing-library/react';
import { RecoilRoot } from 'recoil';
import { RecordTableComponentInstance } from '@/object-record/record-table/components/RecordTableComponentInstance';
import { useCurrentTableCellEditMode } from '../useCurrentTableCellEditMode';
const onColumnsChange = jest.fn();
const recordTableId = 'scopeId';
const Wrapper = ({ children }: { children: React.ReactNode }) => (
<RecoilRoot>
<RecordTableComponentInstance
recordTableId={recordTableId}
onColumnsChange={onColumnsChange}
>
{children}
</RecordTableComponentInstance>
</RecoilRoot>
);
describe('useCurrentTableCellEditMode.', () => {
it('should return initial values', () => {
const { result } = renderHook(() => useCurrentTableCellEditMode(), {
wrapper: Wrapper,
});
expect(result.current.isCurrentTableCellInEditMode).toBe(false);
expect(result.current.setCurrentTableCellInEditMode).toBeInstanceOf(
Function,
);
});
it('should call setCurrentTableCellInEditMode', async () => {
const { result } = renderHook(() => useCurrentTableCellEditMode(), {
wrapper: Wrapper,
});
expect(result.current.isCurrentTableCellInEditMode).toBe(false);
act(() => {
result.current.setCurrentTableCellInEditMode();
});
await waitFor(() => {
expect(result.current.isCurrentTableCellInEditMode).toBe(true);
});
});
});

View File

@ -1,42 +0,0 @@
import { renderHook } from '@testing-library/react';
import { RecoilRoot } from 'recoil';
import { RecordTableComponentInstance } from '@/object-record/record-table/components/RecordTableComponentInstance';
import { RecordTableCellContext } from '@/object-record/record-table/contexts/RecordTableCellContext';
import { RecordTableRowContextProvider } from '@/object-record/record-table/contexts/RecordTableRowContext';
import { RecordTableRowDraggableContextProvider } from '@/object-record/record-table/contexts/RecordTableRowDraggableContext';
import {
recordTableCellContextValue,
recordTableRowContextValue,
recordTableRowDraggableContextValue,
} from '@/object-record/record-table/record-table-cell/hooks/__mocks__/cell';
import { useIsSoftFocusOnCurrentTableCell } from '@/object-record/record-table/record-table-cell/hooks/useIsSoftFocusOnCurrentTableCell';
const Wrapper = ({ children }: { children: React.ReactNode }) => (
<RecoilRoot>
<RecordTableComponentInstance
recordTableId="scopeId"
onColumnsChange={jest.fn()}
>
<RecordTableRowContextProvider value={recordTableRowContextValue}>
<RecordTableRowDraggableContextProvider
value={recordTableRowDraggableContextValue}
>
<RecordTableCellContext.Provider value={recordTableCellContextValue}>
{children}
</RecordTableCellContext.Provider>
</RecordTableRowDraggableContextProvider>
</RecordTableRowContextProvider>
</RecordTableComponentInstance>
</RecoilRoot>
);
describe('useIsSoftFocusOnCurrentTableCell', () => {
it('should work as expected', () => {
const { result } = renderHook(() => useIsSoftFocusOnCurrentTableCell(), {
wrapper: Wrapper,
});
expect(result.current).toBe(false);
});
});

View File

@ -0,0 +1,80 @@
import { renderHook } from '@testing-library/react';
import { act } from 'react';
import { RecoilRoot, useRecoilValue } from 'recoil';
import { RecordTableComponentInstance } from '@/object-record/record-table/components/RecordTableComponentInstance';
import { RecordTableCellContext } from '@/object-record/record-table/contexts/RecordTableCellContext';
import { RecordTableRowContextProvider } from '@/object-record/record-table/contexts/RecordTableRowContext';
import { RecordTableRowDraggableContextProvider } from '@/object-record/record-table/contexts/RecordTableRowDraggableContext';
import {
recordTableCellContextValue,
recordTableRowContextValue,
recordTableRowDraggableContextValue,
} from '@/object-record/record-table/record-table-cell/hooks/__mocks__/cell';
import { useMoveHoverToCurrentCell } from '@/object-record/record-table/record-table-cell/hooks/useMoveHoverToCurrentCell';
import { recordTableHoverPositionComponentState } from '@/object-record/record-table/states/recordTableHoverPositionComponentState';
import { TableHotkeyScope } from '@/object-record/record-table/types/TableHotkeyScope';
import { currentHotkeyScopeState } from '@/ui/utilities/hotkey/states/internal/currentHotkeyScopeState';
const Wrapper = ({ children }: { children: React.ReactNode }) => (
<RecoilRoot
initializeState={({ set }) => {
set(currentHotkeyScopeState, {
scope: TableHotkeyScope.TableFocus,
customScopes: {},
});
}}
>
<RecordTableComponentInstance
recordTableId="test-record-table-instance-id"
onColumnsChange={jest.fn()}
>
<RecordTableRowContextProvider value={recordTableRowContextValue}>
<RecordTableRowDraggableContextProvider
value={recordTableRowDraggableContextValue}
>
<RecordTableCellContext.Provider value={recordTableCellContextValue}>
{children}
</RecordTableCellContext.Provider>
</RecordTableRowDraggableContextProvider>
</RecordTableRowContextProvider>
</RecordTableComponentInstance>
</RecoilRoot>
);
describe('useMoveHoverToCurrentCell', () => {
it('should work as expected', () => {
const { result } = renderHook(
() => {
const recordTableHoverPosition = useRecoilValue(
recordTableHoverPositionComponentState.atomFamily({
instanceId: 'test-record-table-instance-id',
}),
);
const { moveHoverToCurrentCell } = useMoveHoverToCurrentCell(
'test-record-table-instance-id',
);
return {
moveHoverToCurrentCell,
recordTableHoverPosition,
};
},
{
wrapper: Wrapper,
},
);
act(() => {
result.current.moveHoverToCurrentCell({
column: 3,
row: 2,
});
});
expect(result.current.recordTableHoverPosition).toEqual({
column: 3,
row: 2,
});
});
});

View File

@ -1,147 +0,0 @@
import { renderHook } from '@testing-library/react';
import { act } from 'react';
import { CallbackInterface, RecoilRoot } from 'recoil';
import { RecordTableComponentInstance } from '@/object-record/record-table/components/RecordTableComponentInstance';
import { RecordTableCellContext } from '@/object-record/record-table/contexts/RecordTableCellContext';
import { RecordTableRowContextProvider } from '@/object-record/record-table/contexts/RecordTableRowContext';
import { RecordTableRowDraggableContextProvider } from '@/object-record/record-table/contexts/RecordTableRowDraggableContext';
import {
recordTableCellContextValue,
recordTableRowContextValue,
recordTableRowDraggableContextValue,
} from '@/object-record/record-table/record-table-cell/hooks/__mocks__/cell';
import { useMoveSoftFocusToCurrentCellOnHover } from '@/object-record/record-table/record-table-cell/hooks/useMoveSoftFocusToCurrentCellOnHover';
import { TableCellPosition } from '@/object-record/record-table/types/TableCellPosition';
import { TableHotkeyScope } from '@/object-record/record-table/types/TableHotkeyScope';
const mockSoftFocusPositionState = {
key: 'softFocusPositionComponentState__{"instanceId":"scopeId"}',
};
const mockSoftFocusActiveState = {
key: 'isSoftFocusActiveComponentState__{"instanceId":"scopeId"}',
};
const mockIsSoftFocusOnTableCellFamilyStateCurrentPosition = {
key: 'isSoftFocusOnTableCellComponentFamilyState__{"familyKey":{"column":1,"row":0},"instanceId":"scopeId"}',
};
const mockIsSoftFocusOnTableCellFamilyStateNewPosition = {
key: 'isSoftFocusOnTableCellComponentFamilyState__{"familyKey":{"column":3,"row":2},"instanceId":"scopeId"}',
};
const mockCurrentTableCellInEditModePositionState = {
key: 'currentTableCellInEditModePositionComponentState__{"instanceId":"scopeId"}',
};
const mockIsTableCellInEditModeFamilyState = {
key: 'isTableCellInEditModeComponentFamilyState__{"familyKey":{"column":1,"row":0},"instanceId":"scopeId"}',
};
const mockCurrentHotKeyScopeState = {
key: 'currentHotkeyScopeState',
};
const mockCallbackInterface = {
set: jest.fn(),
snapshot: {
getLoadable: (recoilValue: { key: string }) => ({
getValue: () => {
if (recoilValue.key === mockSoftFocusPositionState.key)
return { column: 1, row: 0 };
if (recoilValue.key === mockCurrentTableCellInEditModePositionState.key)
return { column: 1, row: 0 };
else if (recoilValue.key === mockIsTableCellInEditModeFamilyState.key)
return false;
else if (recoilValue.key === mockCurrentHotKeyScopeState.key)
return { scope: TableHotkeyScope.Table };
},
}),
},
} as unknown as CallbackInterface;
const setSoftFocusPosition = jest.fn();
const setOnColumnsChange = jest.fn();
const setHotkeyScope = jest.fn();
jest.mock('recoil', () => ({
...jest.requireActual('recoil'),
useRecoilCallback: (
callback: (
_interface: CallbackInterface,
) => (newPosition: TableCellPosition) => void,
) => callback(mockCallbackInterface),
}));
jest.mock('@/object-record/record-table/hooks/useRecordTable', () => ({
useRecordTable: () => ({
setSoftFocusPosition,
setOnColumnsChange,
}),
}));
jest.mock('@/ui/utilities/hotkey/hooks/useSetHotkeyScope', () => ({
useSetHotkeyScope: () => setHotkeyScope,
}));
const Wrapper = ({ children }: { children: React.ReactNode }) => (
<RecoilRoot>
<RecordTableComponentInstance
recordTableId="scopeId"
onColumnsChange={jest.fn()}
>
<RecordTableRowContextProvider value={recordTableRowContextValue}>
<RecordTableRowDraggableContextProvider
value={recordTableRowDraggableContextValue}
>
<RecordTableCellContext.Provider value={recordTableCellContextValue}>
{children}
</RecordTableCellContext.Provider>
</RecordTableRowDraggableContextProvider>
</RecordTableRowContextProvider>
</RecordTableComponentInstance>
</RecoilRoot>
);
describe('useMoveSoftFocusToCurrentCellOnHover', () => {
it('should work as expected', () => {
const { result } = renderHook(
() => useMoveSoftFocusToCurrentCellOnHover('scopeId'),
{ wrapper: Wrapper },
);
act(() => {
result.current.moveSoftFocusToCurrentCell({
column: 3,
row: 2,
});
});
expect(mockCallbackInterface.set).toHaveBeenNthCalledWith(
1,
mockSoftFocusActiveState,
true,
);
expect(mockCallbackInterface.set).toHaveBeenNthCalledWith(
2,
mockIsSoftFocusOnTableCellFamilyStateCurrentPosition,
false,
);
expect(mockCallbackInterface.set).toHaveBeenNthCalledWith(
3,
mockSoftFocusPositionState,
{ column: 3, row: 2 },
);
expect(mockCallbackInterface.set).toHaveBeenNthCalledWith(
4,
mockIsSoftFocusOnTableCellFamilyStateNewPosition,
true,
);
expect(mockCallbackInterface.set).toHaveBeenNthCalledWith(
5,
mockSoftFocusActiveState,
true,
);
expect(setHotkeyScope).toHaveBeenCalledWith(
TableHotkeyScope.TableSoftFocus,
);
});
});

View File

@ -1,63 +0,0 @@
import { act, renderHook } from '@testing-library/react';
import { CallbackInterface, RecoilRoot } from 'recoil';
import { TableCellPosition } from '@/object-record/record-table/types/TableCellPosition';
import { useSelectedTableCellEditMode } from '../useSelectedTableCellEditMode';
const scopeId = 'yourScopeId';
const mockCallbackInterface = {
set: jest.fn(),
snapshot: {
getLoadable: () => ({
getValue: () => ({ row: 0, column: 0 }),
}),
},
} as unknown as CallbackInterface;
jest.mock('recoil', () => ({
...jest.requireActual('recoil'),
useRecoilCallback: (
callback: (
_interface: CallbackInterface,
) => (newPosition: TableCellPosition) => void,
) => callback(mockCallbackInterface),
}));
describe('useSelectedTableCellEditMode', () => {
it('should have property setSelectedTableCellEditMode', async () => {
const tableCellPosition: TableCellPosition = {
row: 1,
column: 5,
};
const { result } = renderHook(
() => useSelectedTableCellEditMode({ scopeId }),
{
wrapper: RecoilRoot,
},
);
act(() => {
result.current.setSelectedTableCellEditMode(
tableCellPosition.row,
tableCellPosition.column,
);
});
expect(mockCallbackInterface.set).toHaveBeenCalledWith(
{
key: 'isTableCellInEditModeComponentFamilyState__{"familyKey":{"column":0,"row":0},"instanceId":"yourScopeId"}',
},
false,
);
expect(mockCallbackInterface.set).toHaveBeenCalledWith(
{
key: 'isTableCellInEditModeComponentFamilyState__{"familyKey":{"column":5,"row":1},"instanceId":"yourScopeId"}',
},
true,
);
});
});

View File

@ -0,0 +1,155 @@
import { renderHook } from '@testing-library/react';
import React, { act } from 'react';
import { RecoilRoot, useRecoilValue } from 'recoil';
import { RecordTableComponentInstance } from '@/object-record/record-table/components/RecordTableComponentInstance';
import { useSetIsRecordTableFocusActive } from '@/object-record/record-table/record-table-cell/hooks/useSetIsRecordTableFocusActive';
import { isRecordTableFocusActiveComponentState } from '@/object-record/record-table/states/isRecordTableFocusActiveComponentState';
import { recordTableFocusPositionComponentState } from '@/object-record/record-table/states/recordTableFocusPositionComponentState';
import { TableCellPosition } from '@/object-record/record-table/types/TableCellPosition';
const mockClassList = {
add: jest.fn(),
remove: jest.fn(),
};
const mockGetElementById = jest.spyOn(document, 'getElementById');
const Wrapper = ({ children }: { children: React.ReactNode }) => (
<RecoilRoot
initializeState={({ set }) => {
set(
isRecordTableFocusActiveComponentState.atomFamily({
instanceId: 'test-table-id',
}),
false,
);
set(
recordTableFocusPositionComponentState.atomFamily({
instanceId: 'test-table-id',
}),
{
column: 1,
row: 0,
},
);
}}
>
<RecordTableComponentInstance
recordTableId="test-table-id"
onColumnsChange={jest.fn()}
>
{children}
</RecordTableComponentInstance>
</RecoilRoot>
);
const renderHooks = () => {
const { result } = renderHook(
() => {
const { setIsFocusActive, setIsFocusActiveForCurrentPosition } =
useSetIsRecordTableFocusActive('test-table-id');
const isRecordTableFocusActive = useRecoilValue(
isRecordTableFocusActiveComponentState.atomFamily({
instanceId: 'test-table-id',
}),
);
const focusPosition = useRecoilValue(
recordTableFocusPositionComponentState.atomFamily({
instanceId: 'test-table-id',
}),
);
return {
setIsFocusActive,
setIsFocusActiveForCurrentPosition,
isRecordTableFocusActive,
focusPosition,
};
},
{ wrapper: Wrapper },
);
return { result };
};
describe('useSetIsRecordTableFocusActive', () => {
beforeEach(() => {
jest.clearAllMocks();
mockGetElementById.mockReturnValue({
classList: mockClassList,
} as unknown as HTMLElement);
});
it('should set focus active state and add class to cell element when focus is activated', () => {
const { result } = renderHooks();
const cellPosition: TableCellPosition = { column: 1, row: 0 };
act(() => {
result.current.setIsFocusActive(true, cellPosition);
});
expect(mockGetElementById).toHaveBeenCalledWith('record-table-cell-1-0');
expect(mockClassList.add).toHaveBeenCalledWith('focus-active');
expect(result.current.isRecordTableFocusActive).toBe(true);
expect(result.current.focusPosition).toEqual(cellPosition);
});
it('should remove focus-active class when focus is deactivated and update isRecordTableFocusActiveComponentState', () => {
const { result } = renderHooks();
const cellPosition: TableCellPosition = { column: 1, row: 0 };
act(() => {
result.current.setIsFocusActive(false, cellPosition);
});
expect(mockGetElementById).toHaveBeenCalledWith('record-table-cell-1-0');
expect(mockClassList.remove).toHaveBeenCalledWith('focus-active');
expect(result.current.isRecordTableFocusActive).toBe(false);
expect(result.current.focusPosition).toEqual(cellPosition);
});
it('should set focus for current position', () => {
const { result } = renderHooks();
act(() => {
result.current.setIsFocusActiveForCurrentPosition(true);
});
expect(mockGetElementById).toHaveBeenCalledWith('record-table-cell-1-0');
expect(mockClassList.add).toHaveBeenCalledWith('focus-active');
expect(result.current.isRecordTableFocusActive).toBe(true);
expect(result.current.focusPosition).toEqual({ column: 1, row: 0 });
});
it('should handle case when the cell element is not found', () => {
mockGetElementById.mockReturnValue(null);
const { result } = renderHooks();
const cellPosition: TableCellPosition = { column: 1, row: 0 };
act(() => {
result.current.setIsFocusActive(true, cellPosition);
});
expect(mockGetElementById).toHaveBeenCalledWith('record-table-cell-1-0');
expect(mockClassList.add).not.toHaveBeenCalled();
expect(result.current.isRecordTableFocusActive).toBe(true);
expect(result.current.focusPosition).toEqual(cellPosition);
});
});

View File

@ -16,10 +16,8 @@ import {
recordTableRowDraggableContextValue,
} from '@/object-record/record-table/record-table-cell/hooks/__mocks__/cell';
import { useCloseRecordTableCellInGroup } from '@/object-record/record-table/record-table-cell/hooks/internal/useCloseRecordTableCellInGroup';
import { currentTableCellInEditModePositionComponentState } from '@/object-record/record-table/states/currentTableCellInEditModePositionComponentState';
import { isTableCellInEditModeComponentFamilyState } from '@/object-record/record-table/states/isTableCellInEditModeComponentFamilyState';
import { recordTableCellEditModePositionComponentState } from '@/object-record/record-table/states/recordTableCellEditModePositionComponentState';
import { useDragSelect } from '@/ui/utilities/drag-select/hooks/useDragSelect';
import { useRecoilComponentFamilyValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentFamilyValueV2';
import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2';
import { generatedMockObjectMetadataItems } from '~/testing/mock-data/generatedMockObjectMetadataItems';
@ -60,7 +58,7 @@ const Wrapper = ({ children }: { children: React.ReactNode }) => (
value={recordTableRowDraggableContextValue}
>
<RecordTableCellContext.Provider
value={{ ...recordTableCellContextValue, columnIndex: 0 }}
value={{ ...recordTableCellContextValue }}
>
{children}
</RecordTableCellContext.Provider>
@ -77,16 +75,12 @@ describe('useCloseRecordTableCellInGroup', () => {
const { result } = renderHook(
() => {
const currentTableCellInEditModePosition = useRecoilComponentValueV2(
currentTableCellInEditModePositionComponentState,
);
const isTableCellInEditMode = useRecoilComponentFamilyValueV2(
isTableCellInEditModeComponentFamilyState,
currentTableCellInEditModePosition,
recordTableCellEditModePositionComponentState,
);
return {
...useCloseRecordTableCellInGroup(),
...useDragSelect(),
isTableCellInEditMode,
currentTableCellInEditModePosition,
};
},
{
@ -99,7 +93,7 @@ describe('useCloseRecordTableCellInGroup', () => {
});
expect(result.current.isDragSelectionStartEnabled()).toBe(true);
expect(result.current.isTableCellInEditMode).toBe(false);
expect(setHotkeyScope).toHaveBeenCalledWith('table-soft-focus');
expect(result.current.currentTableCellInEditModePosition).toBe(null);
expect(setHotkeyScope).toHaveBeenCalledWith('table-focus');
});
});

View File

@ -16,10 +16,8 @@ import {
recordTableRowDraggableContextValue,
} from '@/object-record/record-table/record-table-cell/hooks/__mocks__/cell';
import { useCloseRecordTableCellNoGroup } from '@/object-record/record-table/record-table-cell/hooks/internal/useCloseRecordTableCellNoGroup';
import { currentTableCellInEditModePositionComponentState } from '@/object-record/record-table/states/currentTableCellInEditModePositionComponentState';
import { isTableCellInEditModeComponentFamilyState } from '@/object-record/record-table/states/isTableCellInEditModeComponentFamilyState';
import { recordTableCellEditModePositionComponentState } from '@/object-record/record-table/states/recordTableCellEditModePositionComponentState';
import { useDragSelect } from '@/ui/utilities/drag-select/hooks/useDragSelect';
import { useRecoilComponentFamilyValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentFamilyValueV2';
import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2';
import { generatedMockObjectMetadataItems } from '~/testing/mock-data/generatedMockObjectMetadataItems';
@ -60,7 +58,7 @@ const Wrapper = ({ children }: { children: React.ReactNode }) => (
value={recordTableRowDraggableContextValue}
>
<RecordTableCellContext.Provider
value={{ ...recordTableCellContextValue, columnIndex: 0 }}
value={{ ...recordTableCellContextValue }}
>
{children}
</RecordTableCellContext.Provider>
@ -77,16 +75,13 @@ describe('useCloseRecordTableCellNoGroup', () => {
const { result } = renderHook(
() => {
const currentTableCellInEditModePosition = useRecoilComponentValueV2(
currentTableCellInEditModePositionComponentState,
);
const isTableCellInEditMode = useRecoilComponentFamilyValueV2(
isTableCellInEditModeComponentFamilyState,
currentTableCellInEditModePosition,
recordTableCellEditModePositionComponentState,
);
return {
...useCloseRecordTableCellNoGroup(),
...useDragSelect(),
isTableCellInEditMode,
currentTableCellInEditModePosition,
};
},
{
@ -99,7 +94,7 @@ describe('useCloseRecordTableCellNoGroup', () => {
});
expect(result.current.isDragSelectionStartEnabled()).toBe(true);
expect(result.current.isTableCellInEditMode).toBe(false);
expect(setHotkeyScope).toHaveBeenCalledWith('table-soft-focus');
expect(result.current.currentTableCellInEditModePosition).toBe(null);
expect(setHotkeyScope).toHaveBeenCalledWith('table-focus');
});
});

View File

@ -1,6 +1,6 @@
import { useRecoilCallback } from 'recoil';
import { SOFT_FOCUS_CLICK_OUTSIDE_LISTENER_ID } from '@/object-record/record-table/constants/SoftFocusClickOutsideListenerId';
import { FOCUS_CLICK_OUTSIDE_LISTENER_ID } from '@/object-record/record-table/constants/FocusClickOutsideListenerId';
import { useDragSelect } from '@/ui/utilities/drag-select/hooks/useDragSelect';
import { useSetHotkeyScope } from '@/ui/utilities/hotkey/hooks/useSetHotkeyScope';
import { useClickOutsideListener } from '@/ui/utilities/pointer-event/hooks/useClickOutsideListener';
@ -16,7 +16,7 @@ export const useCloseRecordTableCellInGroup = () => {
const { setDragSelectionStartEnabled } = useDragSelect();
const { toggleClickOutsideListener } = useClickOutsideListener(
SOFT_FOCUS_CLICK_OUTSIDE_LISTENER_ID,
FOCUS_CLICK_OUTSIDE_LISTENER_ID,
);
const closeCurrentTableCellInEditMode =
@ -27,7 +27,7 @@ export const useCloseRecordTableCellInGroup = () => {
toggleClickOutsideListener(true);
setDragSelectionStartEnabled(true);
closeCurrentTableCellInEditMode();
setHotkeyScope(TableHotkeyScope.TableSoftFocus);
setHotkeyScope(TableHotkeyScope.TableFocus);
},
[
closeCurrentTableCellInEditMode,

View File

@ -1,4 +1,4 @@
import { SOFT_FOCUS_CLICK_OUTSIDE_LISTENER_ID } from '@/object-record/record-table/constants/SoftFocusClickOutsideListenerId';
import { FOCUS_CLICK_OUTSIDE_LISTENER_ID } from '@/object-record/record-table/constants/FocusClickOutsideListenerId';
import { useDragSelect } from '@/ui/utilities/drag-select/hooks/useDragSelect';
import { useSetHotkeyScope } from '@/ui/utilities/hotkey/hooks/useSetHotkeyScope';
import { useClickOutsideListener } from '@/ui/utilities/pointer-event/hooks/useClickOutsideListener';
@ -16,7 +16,7 @@ export const useCloseRecordTableCellNoGroup = () => {
const { setDragSelectionStartEnabled } = useDragSelect();
const { toggleClickOutsideListener } = useClickOutsideListener(
SOFT_FOCUS_CLICK_OUTSIDE_LISTENER_ID,
FOCUS_CLICK_OUTSIDE_LISTENER_ID,
);
const closeCurrentTableCellInEditMode =
@ -26,7 +26,7 @@ export const useCloseRecordTableCellNoGroup = () => {
toggleClickOutsideListener(true);
setDragSelectionStartEnabled(true);
closeCurrentTableCellInEditMode();
setHotkeyScope(TableHotkeyScope.TableSoftFocus);
setHotkeyScope(TableHotkeyScope.TableFocus);
}, [
closeCurrentTableCellInEditMode,
setDragSelectionStartEnabled,

View File

@ -1,9 +0,0 @@
import { useContext } from 'react';
import { RecordTableCellContext } from '@/object-record/record-table/contexts/RecordTableCellContext';
export const useCurrentTableCellPosition = () => {
const { cellPosition } = useContext(RecordTableCellContext);
return cellPosition;
};

View File

@ -1,27 +0,0 @@
import { useCallback } from 'react';
import { useMoveEditModeToTableCellPosition } from '../../hooks/internal/useMoveEditModeToCellPosition';
import { isTableCellInEditModeComponentFamilyState } from '@/object-record/record-table/states/isTableCellInEditModeComponentFamilyState';
import { useRecoilComponentFamilyValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentFamilyValueV2';
import { useCurrentTableCellPosition } from './useCurrentCellPosition';
export const useCurrentTableCellEditMode = () => {
const moveEditModeToTableCellPosition = useMoveEditModeToTableCellPosition();
const currentTableCellPosition = useCurrentTableCellPosition();
const isCurrentTableCellInEditMode = useRecoilComponentFamilyValueV2(
isTableCellInEditModeComponentFamilyState,
currentTableCellPosition,
);
const setCurrentTableCellInEditMode = useCallback(() => {
moveEditModeToTableCellPosition(currentTableCellPosition);
}, [currentTableCellPosition, moveEditModeToTableCellPosition]);
return {
isCurrentTableCellInEditMode,
setCurrentTableCellInEditMode,
};
};

View File

@ -1,14 +0,0 @@
import { isSoftFocusOnTableCellComponentFamilyState } from '@/object-record/record-table/states/isSoftFocusOnTableCellComponentFamilyState';
import { useRecoilComponentFamilyValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentFamilyValueV2';
import { useCurrentTableCellPosition } from './useCurrentCellPosition';
export const useIsSoftFocusOnCurrentTableCell = () => {
const currentTableCellPosition = useCurrentTableCellPosition();
const isSoftFocusOnTableCell = useRecoilComponentFamilyValueV2(
isSoftFocusOnTableCellComponentFamilyState,
currentTableCellPosition,
);
return isSoftFocusOnTableCell;
};

View File

@ -0,0 +1,55 @@
import { useRecoilCallback } from 'recoil';
import { TableCellPosition } from '@/object-record/record-table/types/TableCellPosition';
import { currentHotkeyScopeState } from '@/ui/utilities/hotkey/states/internal/currentHotkeyScopeState';
import { getSnapshotValue } from '@/ui/utilities/recoil-scope/utils/getSnapshotValue';
import { recordTableHoverPositionComponentState } from '@/object-record/record-table/states/recordTableHoverPositionComponentState';
import { isSomeCellInEditModeComponentSelector } from '@/object-record/record-table/states/selectors/isSomeCellInEditModeComponentSelector';
import { AppHotkeyScope } from '@/ui/utilities/hotkey/types/AppHotkeyScope';
import { useRecoilComponentCallbackStateV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentCallbackStateV2';
import { useSetRecoilComponentStateV2 } from '@/ui/utilities/state/component-state/hooks/useSetRecoilComponentStateV2';
import { TableHotkeyScope } from '../../types/TableHotkeyScope';
export const useMoveHoverToCurrentCell = (recordTableId: string) => {
const setHoverPosition = useSetRecoilComponentStateV2(
recordTableHoverPositionComponentState,
recordTableId,
);
const isSomeCellInEditModeSelector = useRecoilComponentCallbackStateV2(
isSomeCellInEditModeComponentSelector,
recordTableId,
);
const moveHoverToCurrentCell = useRecoilCallback(
({ snapshot }) =>
(cellPosition: TableCellPosition) => {
const isSomeCellInEditMode = getSnapshotValue(
snapshot,
isSomeCellInEditModeSelector,
);
const currentHotkeyScope = getSnapshotValue(
snapshot,
currentHotkeyScopeState,
);
if (
currentHotkeyScope.scope !== TableHotkeyScope.TableFocus &&
currentHotkeyScope.scope !== TableHotkeyScope.CellEditMode &&
currentHotkeyScope.scope !== TableHotkeyScope.Table &&
currentHotkeyScope.scope !== AppHotkeyScope.CommandMenuOpen
) {
return;
}
if (!isSomeCellInEditMode) {
setHoverPosition(cellPosition);
}
},
[isSomeCellInEditModeSelector, setHoverPosition],
);
return { moveHoverToCurrentCell };
};

View File

@ -1,68 +0,0 @@
import { useRecoilCallback } from 'recoil';
import { useSetSoftFocus } from '@/object-record/record-table/record-table-cell/hooks/useSetSoftFocus';
import { TableCellPosition } from '@/object-record/record-table/types/TableCellPosition';
import { currentHotkeyScopeState } from '@/ui/utilities/hotkey/states/internal/currentHotkeyScopeState';
import { getSnapshotValue } from '@/ui/utilities/recoil-scope/utils/getSnapshotValue';
import { currentTableCellInEditModePositionComponentState } from '@/object-record/record-table/states/currentTableCellInEditModePositionComponentState';
import { isTableCellInEditModeComponentFamilyState } from '@/object-record/record-table/states/isTableCellInEditModeComponentFamilyState';
import { AppHotkeyScope } from '@/ui/utilities/hotkey/types/AppHotkeyScope';
import { useRecoilComponentCallbackStateV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentCallbackStateV2';
import { TableHotkeyScope } from '../../types/TableHotkeyScope';
export const useMoveSoftFocusToCurrentCellOnHover = (recordTableId: string) => {
const setSoftFocus = useSetSoftFocus(recordTableId);
const currentTableCellInEditModePositionState =
useRecoilComponentCallbackStateV2(
currentTableCellInEditModePositionComponentState,
recordTableId,
);
const isTableCellInEditModeFamilyState = useRecoilComponentCallbackStateV2(
isTableCellInEditModeComponentFamilyState,
recordTableId,
);
const moveSoftFocusToCurrentCell = useRecoilCallback(
({ snapshot }) =>
(cellPosition: TableCellPosition) => {
const currentTableCellInEditModePosition = getSnapshotValue(
snapshot,
currentTableCellInEditModePositionState,
);
const isSomeCellInEditMode = snapshot
.getLoadable(
isTableCellInEditModeFamilyState(
currentTableCellInEditModePosition,
),
)
.getValue();
const currentHotkeyScope = snapshot
.getLoadable(currentHotkeyScopeState)
.getValue();
if (
currentHotkeyScope.scope !== TableHotkeyScope.TableSoftFocus &&
currentHotkeyScope.scope !== TableHotkeyScope.CellEditMode &&
currentHotkeyScope.scope !== TableHotkeyScope.Table &&
currentHotkeyScope.scope !== AppHotkeyScope.CommandMenuOpen
) {
return;
}
if (!isSomeCellInEditMode) {
setSoftFocus(cellPosition);
}
},
[
currentTableCellInEditModePositionState,
isTableCellInEditModeFamilyState,
setSoftFocus,
],
);
return { moveSoftFocusToCurrentCell };
};

View File

@ -4,11 +4,12 @@ import { FieldContext } from '@/object-record/record-field/contexts/FieldContext
import { FieldDefinition } from '@/object-record/record-field/types/FieldDefinition';
import { FieldMetadata } from '@/object-record/record-field/types/FieldMetadata';
import { useRecordTableRowContextOrThrow } from '@/object-record/record-table/contexts/RecordTableRowContext';
import { useCurrentTableCellPosition } from '@/object-record/record-table/record-table-cell/hooks/useCurrentCellPosition';
import { TableCellPosition } from '@/object-record/record-table/types/TableCellPosition';
import { HotkeyScope } from '@/ui/utilities/hotkey/types/HotkeyScope';
import { useRecordTableBodyContextOrThrow } from '@/object-record/record-table/contexts/RecordTableBodyContext';
import { RecordTableCellContext } from '@/object-record/record-table/contexts/RecordTableCellContext';
import { useSetRecordTableFocusPosition } from '@/object-record/record-table/hooks/internal/useSetRecordTableFocusPosition';
import { TableHotkeyScope } from '../../types/TableHotkeyScope';
export const DEFAULT_CELL_SCOPE: HotkeyScope = {
@ -33,7 +34,9 @@ export const useOpenRecordTableCellFromCell = () => {
const { onOpenTableCell } = useRecordTableBodyContextOrThrow();
const cellPosition = useCurrentTableCellPosition();
const { cellPosition } = useContext(RecordTableCellContext);
const setFocusPosition = useSetRecordTableFocusPosition();
const openTableCell = (
initialValue?: string,
@ -51,6 +54,8 @@ export const useOpenRecordTableCellFromCell = () => {
isActionButtonClick,
isNavigating,
});
setFocusPosition(cellPosition);
};
return {

View File

@ -6,9 +6,8 @@ import { FieldMetadata } from '@/object-record/record-field/types/FieldMetadata'
import { isFieldValueEmpty } from '@/object-record/record-field/utils/isFieldValueEmpty';
import { viewableRecordIdState } from '@/object-record/record-right-drawer/states/viewableRecordIdState';
import { recordStoreFamilySelector } from '@/object-record/record-store/states/selectors/recordStoreFamilySelector';
import { SOFT_FOCUS_CLICK_OUTSIDE_LISTENER_ID } from '@/object-record/record-table/constants/SoftFocusClickOutsideListenerId';
import { FOCUS_CLICK_OUTSIDE_LISTENER_ID } from '@/object-record/record-table/constants/FocusClickOutsideListenerId';
import { useLeaveTableFocus } from '@/object-record/record-table/hooks/internal/useLeaveTableFocus';
import { useMoveEditModeToTableCellPosition } from '@/object-record/record-table/hooks/internal/useMoveEditModeToCellPosition';
import { TableCellPosition } from '@/object-record/record-table/types/TableCellPosition';
import { useDragSelect } from '@/ui/utilities/drag-select/hooks/useDragSelect';
import { HotkeyScope } from '@/ui/utilities/hotkey/types/HotkeyScope';
@ -21,14 +20,15 @@ import { useRecordIndexContextOrThrow } from '@/object-record/record-index/conte
import { recordIndexOpenRecordInState } from '@/object-record/record-index/states/recordIndexOpenRecordInState';
import { viewableRecordNameSingularState } from '@/object-record/record-right-drawer/states/viewableRecordNameSingularState';
import { RECORD_TABLE_CLICK_OUTSIDE_LISTENER_ID } from '@/object-record/record-table/constants/RecordTableClickOutsideListenerId';
import { recordTableCellEditModePositionComponentState } from '@/object-record/record-table/states/recordTableCellEditModePositionComponentState';
import { getDropdownFocusIdForRecordField } from '@/object-record/utils/getDropdownFocusIdForRecordField';
import { getRecordFieldInputId } from '@/object-record/utils/getRecordFieldInputId';
import { useSetActiveDropdownFocusIdAndMemorizePrevious } from '@/ui/layout/dropdown/hooks/useSetFocusedDropdownIdAndMemorizePrevious';
import { useClickOustideListenerStates } from '@/ui/utilities/pointer-event/hooks/useClickOustideListenerStates';
import { useSetRecoilComponentStateV2 } from '@/ui/utilities/state/component-state/hooks/useSetRecoilComponentStateV2';
import { ViewOpenRecordInType } from '@/views/types/ViewOpenRecordInType';
import { useNavigate } from 'react-router-dom';
import { TableHotkeyScope } from '../../types/TableHotkeyScope';
export const DEFAULT_CELL_SCOPE: HotkeyScope = {
scope: TableHotkeyScope.CellEditMode,
};
@ -50,14 +50,16 @@ export const useOpenRecordTableCellV2 = (tableScopeId: string) => {
useClickOustideListenerStates(RECORD_TABLE_CLICK_OUTSIDE_LISTENER_ID);
const { indexIdentifierUrl } = useRecordIndexContextOrThrow();
const moveEditModeToTableCellPosition =
useMoveEditModeToTableCellPosition(tableScopeId);
const setCurrentTableCellInEditModePosition = useSetRecoilComponentStateV2(
recordTableCellEditModePositionComponentState,
tableScopeId,
);
const { setDragSelectionStartEnabled } = useDragSelect();
const leaveTableFocus = useLeaveTableFocus(tableScopeId);
const { toggleClickOutsideListener } = useClickOutsideListener(
SOFT_FOCUS_CLICK_OUTSIDE_LISTENER_ID,
FOCUS_CLICK_OUTSIDE_LISTENER_ID,
);
const initDraftValue = useInitDraftValueV2();
@ -148,7 +150,7 @@ export const useOpenRecordTableCellV2 = (tableScopeId: string) => {
recordId,
});
moveEditModeToTableCellPosition(cellPosition);
setCurrentTableCellInEditModePosition(cellPosition);
initDraftValue({
value: initialValue,
@ -175,7 +177,7 @@ export const useOpenRecordTableCellV2 = (tableScopeId: string) => {
getClickOutsideListenerIsActivatedState,
setDragSelectionStartEnabled,
openFieldInput,
moveEditModeToTableCellPosition,
setCurrentTableCellInEditModePosition,
initDraftValue,
toggleClickOutsideListener,
setActiveDropdownFocusIdAndMemorizePrevious,

View File

@ -1,21 +0,0 @@
import { useCallback } from 'react';
import { useMoveEditModeToTableCellPosition } from '../../hooks/internal/useMoveEditModeToCellPosition';
export const useSelectedTableCellEditMode = ({
scopeId,
}: {
scopeId: string;
}) => {
const moveEditModeToTableCellPosition =
useMoveEditModeToTableCellPosition(scopeId);
const setSelectedTableCellEditMode = useCallback(
(row: number, column: number) => {
moveEditModeToTableCellPosition({ column, row });
},
[moveEditModeToTableCellPosition],
);
return { setSelectedTableCellEditMode };
};

View File

@ -0,0 +1,51 @@
import { isRecordTableFocusActiveComponentState } from '@/object-record/record-table/states/isRecordTableFocusActiveComponentState';
import { recordTableFocusPositionComponentState } from '@/object-record/record-table/states/recordTableFocusPositionComponentState';
import { TableCellPosition } from '@/object-record/record-table/types/TableCellPosition';
import { useRecoilComponentCallbackStateV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentCallbackStateV2';
import { useRecoilCallback } from 'recoil';
export const useSetIsRecordTableFocusActive = (recordTableId?: string) => {
const isRecordTableFocusActiveState = useRecoilComponentCallbackStateV2(
isRecordTableFocusActiveComponentState,
recordTableId,
);
const focusPositionState = useRecoilComponentCallbackStateV2(
recordTableFocusPositionComponentState,
recordTableId,
);
const setIsFocusActive = useRecoilCallback(
({ set }) =>
(isRecordTableFocusActive: boolean, cellPosition: TableCellPosition) => {
const cellId = `record-table-cell-${cellPosition.column}-${cellPosition.row}`;
const cellElement = document.getElementById(cellId);
if (isRecordTableFocusActive) {
cellElement?.classList.add('focus-active');
}
if (!isRecordTableFocusActive) {
cellElement?.classList.remove('focus-active');
}
set(isRecordTableFocusActiveState, isRecordTableFocusActive);
},
[isRecordTableFocusActiveState],
);
const setIsFocusActiveForCurrentPosition = useRecoilCallback(
({ snapshot }) =>
(isRecordTableFocusActive: boolean) => {
const currentPosition = snapshot
.getLoadable(focusPositionState)
.getValue();
setIsFocusActive(isRecordTableFocusActive, currentPosition);
},
[setIsFocusActive, focusPositionState],
);
return { setIsFocusActive, setIsFocusActiveForCurrentPosition };
};

View File

@ -1,39 +0,0 @@
import { useRecoilCallback } from 'recoil';
import { useSetSoftFocusPosition } from '@/object-record/record-table/hooks/internal/useSetSoftFocusPosition';
import { TableCellPosition } from '@/object-record/record-table/types/TableCellPosition';
import { useSetHotkeyScope } from '@/ui/utilities/hotkey/hooks/useSetHotkeyScope';
import { isSoftFocusActiveComponentState } from '@/object-record/record-table/states/isSoftFocusActiveComponentState';
import { currentHotkeyScopeState } from '@/ui/utilities/hotkey/states/internal/currentHotkeyScopeState';
import { AppHotkeyScope } from '@/ui/utilities/hotkey/types/AppHotkeyScope';
import { useRecoilComponentCallbackStateV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentCallbackStateV2';
import { TableHotkeyScope } from '../../types/TableHotkeyScope';
export const useSetSoftFocus = (recordTableId?: string) => {
const setSoftFocusPosition = useSetSoftFocusPosition(recordTableId);
const isSoftFocusActiveState = useRecoilComponentCallbackStateV2(
isSoftFocusActiveComponentState,
recordTableId,
);
const setHotkeyScope = useSetHotkeyScope();
return useRecoilCallback(
({ snapshot, set }) =>
(newPosition: TableCellPosition) => {
setSoftFocusPosition(newPosition);
set(isSoftFocusActiveState, true);
if (
snapshot.getLoadable(currentHotkeyScopeState).getValue().scope !==
AppHotkeyScope.CommandMenuOpen
) {
setHotkeyScope(TableHotkeyScope.TableSoftFocus);
}
},
[setSoftFocusPosition, isSoftFocusActiveState, setHotkeyScope],
);
};

View File

@ -1,13 +0,0 @@
import { useSetSoftFocus } from '@/object-record/record-table/record-table-cell/hooks/useSetSoftFocus';
import { useCurrentTableCellPosition } from './useCurrentCellPosition';
export const useSetSoftFocusOnCurrentTableCell = () => {
const setSoftFocus = useSetSoftFocus();
const currentTableCellPosition = useCurrentTableCellPosition();
return () => {
setSoftFocus(currentTableCellPosition);
};
};

View File

@ -1,8 +1,9 @@
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,
});
export const isRecordTableFocusActiveComponentState =
createComponentStateV2<boolean>({
key: 'isRecordTableFocusActiveComponentState',
defaultValue: false,
componentInstanceContext: RecordTableComponentInstanceContext,
});

View File

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

View File

@ -1,10 +0,0 @@
import { RecordTableComponentInstanceContext } from '@/object-record/record-table/states/context/RecordTableComponentInstanceContext';
import { createComponentFamilyStateV2 } from '@/ui/utilities/state/component-state/utils/createComponentFamilyStateV2';
import { TableCellPosition } from '../types/TableCellPosition';
export const isSoftFocusOnTableCellComponentFamilyState =
createComponentFamilyStateV2<boolean, TableCellPosition>({
key: 'isSoftFocusOnTableCellComponentFamilyState',
defaultValue: false,
componentInstanceContext: RecordTableComponentInstanceContext,
});

View File

@ -1,5 +0,0 @@
import { createState } from 'twenty-ui/utilities';
export const isSoftFocusUsingMouseState = createState<boolean>({
key: 'isSoftFocusUsingMouseState',
defaultValue: false,
});

View File

@ -1,10 +0,0 @@
import { RecordTableComponentInstanceContext } from '@/object-record/record-table/states/context/RecordTableComponentInstanceContext';
import { createComponentFamilyStateV2 } from '@/ui/utilities/state/component-state/utils/createComponentFamilyStateV2';
import { TableCellPosition } from '../types/TableCellPosition';
export const isTableCellInEditModeComponentFamilyState =
createComponentFamilyStateV2<boolean, TableCellPosition>({
key: 'isTableCellInEditModeComponentFamilyState',
defaultValue: false,
componentInstanceContext: RecordTableComponentInstanceContext,
});

View File

@ -2,12 +2,9 @@ import { RecordTableComponentInstanceContext } from '@/object-record/record-tabl
import { createComponentStateV2 } from '@/ui/utilities/state/component-state/utils/createComponentStateV2';
import { TableCellPosition } from '../types/TableCellPosition';
export const currentTableCellInEditModePositionComponentState =
createComponentStateV2<TableCellPosition>({
key: 'currentTableCellInEditModePositionComponentState',
defaultValue: {
row: 0,
column: 1,
},
export const recordTableCellEditModePositionComponentState =
createComponentStateV2<TableCellPosition | null>({
key: 'recordTableCellEditModePositionComponentState',
defaultValue: null,
componentInstanceContext: RecordTableComponentInstanceContext,
});

View File

@ -2,9 +2,9 @@ import { RecordTableComponentInstanceContext } from '@/object-record/record-tabl
import { createComponentStateV2 } from '@/ui/utilities/state/component-state/utils/createComponentStateV2';
import { TableCellPosition } from '../types/TableCellPosition';
export const softFocusPositionComponentState =
export const recordTableFocusPositionComponentState =
createComponentStateV2<TableCellPosition>({
key: 'softFocusPositionComponentState',
key: 'recordTableFocusPositionComponentState',
defaultValue: {
row: 0,
column: 1,

View File

@ -0,0 +1,10 @@
import { RecordTableComponentInstanceContext } from '@/object-record/record-table/states/context/RecordTableComponentInstanceContext';
import { createComponentStateV2 } from '@/ui/utilities/state/component-state/utils/createComponentStateV2';
import { TableCellPosition } from '../types/TableCellPosition';
export const recordTableHoverPositionComponentState =
createComponentStateV2<TableCellPosition | null>({
key: 'recordTableHoverPositionComponentState',
defaultValue: null,
componentInstanceContext: RecordTableComponentInstanceContext,
});

View File

@ -0,0 +1,20 @@
import { RecordTableComponentInstanceContext } from '@/object-record/record-table/states/context/RecordTableComponentInstanceContext';
import { recordTableCellEditModePositionComponentState } from '@/object-record/record-table/states/recordTableCellEditModePositionComponentState';
import { createComponentSelectorV2 } from '@/ui/utilities/state/component-state/utils/createComponentSelectorV2';
import { isDefined } from 'twenty-shared/utils';
export const isSomeCellInEditModeComponentSelector = createComponentSelectorV2({
key: 'isSomeCellInEditModeComponentSelector',
componentInstanceContext: RecordTableComponentInstanceContext,
get:
({ instanceId }) =>
({ get }) => {
const currentTableCellInEditModePosition = get(
recordTableCellEditModePositionComponentState.atomFamily({
instanceId,
}),
);
return isDefined(currentTableCellInEditModePosition);
},
});

View File

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

View File

@ -2,6 +2,6 @@ export enum TableHotkeyScope {
CellDoubleTextInput = 'cell-double-text-input',
CellEditMode = 'cell-edit-mode',
CellDateEditMode = 'cell-date-edit-mode',
TableSoftFocus = 'table-soft-focus',
TableFocus = 'table-focus',
Table = 'table',
}

View File

@ -85,7 +85,7 @@ const InternalTableContextProviders = ({
onOpenTableCell: () => {},
onActionMenuDropdownOpened: () => {},
onMoveFocus: () => {},
onMoveSoftFocusToCurrentCell: () => {},
onMoveHoverToCurrentCell: () => {},
}}
>
{children}