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:
@ -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}
|
||||
|
||||
@ -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} />
|
||||
)}
|
||||
</>
|
||||
);
|
||||
|
||||
@ -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,
|
||||
},
|
||||
@ -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,
|
||||
}}
|
||||
|
||||
@ -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,
|
||||
}}
|
||||
|
||||
@ -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;
|
||||
};
|
||||
@ -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
|
||||
|
||||
@ -0,0 +1,2 @@
|
||||
export const FOCUS_CLICK_OUTSIDE_LISTENER_ID =
|
||||
'focus-click-outside-listener-id';
|
||||
@ -1,2 +0,0 @@
|
||||
export const SOFT_FOCUS_CLICK_OUTSIDE_LISTENER_ID =
|
||||
'soft-focus-click-outside-listener-id';
|
||||
@ -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,
|
||||
|
||||
@ -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;
|
||||
};
|
||||
|
||||
|
||||
@ -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],
|
||||
);
|
||||
};
|
||||
|
||||
@ -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,
|
||||
],
|
||||
);
|
||||
};
|
||||
@ -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],
|
||||
);
|
||||
};
|
||||
@ -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 {
|
||||
|
||||
@ -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);
|
||||
};
|
||||
};
|
||||
|
||||
@ -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],
|
||||
);
|
||||
};
|
||||
@ -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],
|
||||
);
|
||||
};
|
||||
@ -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,
|
||||
],
|
||||
);
|
||||
};
|
||||
@ -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,
|
||||
|
||||
@ -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,
|
||||
};
|
||||
};
|
||||
|
||||
@ -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);
|
||||
@ -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 <></>;
|
||||
};
|
||||
@ -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>
|
||||
|
||||
@ -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>
|
||||
|
||||
@ -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>
|
||||
);
|
||||
};
|
||||
|
||||
@ -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>
|
||||
|
||||
@ -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>
|
||||
);
|
||||
};
|
||||
|
||||
@ -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}
|
||||
|
||||
@ -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>
|
||||
);
|
||||
};
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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>
|
||||
);
|
||||
};
|
||||
|
||||
@ -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>
|
||||
);
|
||||
};
|
||||
@ -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>
|
||||
);
|
||||
};
|
||||
@ -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,
|
||||
);
|
||||
};
|
||||
@ -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 />}
|
||||
</>
|
||||
);
|
||||
};
|
||||
@ -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}
|
||||
|
||||
@ -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,
|
||||
};
|
||||
|
||||
@ -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,
|
||||
});
|
||||
});
|
||||
});
|
||||
@ -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);
|
||||
});
|
||||
});
|
||||
});
|
||||
@ -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);
|
||||
});
|
||||
});
|
||||
@ -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,
|
||||
});
|
||||
});
|
||||
});
|
||||
@ -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,
|
||||
);
|
||||
});
|
||||
});
|
||||
@ -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,
|
||||
);
|
||||
});
|
||||
});
|
||||
@ -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);
|
||||
});
|
||||
});
|
||||
@ -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');
|
||||
});
|
||||
});
|
||||
|
||||
@ -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');
|
||||
});
|
||||
});
|
||||
|
||||
@ -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,
|
||||
|
||||
@ -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,
|
||||
|
||||
@ -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;
|
||||
};
|
||||
@ -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,
|
||||
};
|
||||
};
|
||||
@ -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;
|
||||
};
|
||||
@ -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 };
|
||||
};
|
||||
@ -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 };
|
||||
};
|
||||
@ -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 {
|
||||
|
||||
@ -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,
|
||||
|
||||
@ -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 };
|
||||
};
|
||||
@ -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 };
|
||||
};
|
||||
@ -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],
|
||||
);
|
||||
};
|
||||
@ -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);
|
||||
};
|
||||
};
|
||||
@ -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,
|
||||
});
|
||||
@ -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,
|
||||
});
|
||||
@ -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,
|
||||
});
|
||||
@ -1,5 +0,0 @@
|
||||
import { createState } from 'twenty-ui/utilities';
|
||||
export const isSoftFocusUsingMouseState = createState<boolean>({
|
||||
key: 'isSoftFocusUsingMouseState',
|
||||
defaultValue: false,
|
||||
});
|
||||
@ -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,
|
||||
});
|
||||
@ -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,
|
||||
});
|
||||
@ -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,
|
||||
@ -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,
|
||||
});
|
||||
@ -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);
|
||||
},
|
||||
});
|
||||
@ -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,
|
||||
});
|
||||
@ -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',
|
||||
}
|
||||
|
||||
@ -85,7 +85,7 @@ const InternalTableContextProviders = ({
|
||||
onOpenTableCell: () => {},
|
||||
onActionMenuDropdownOpened: () => {},
|
||||
onMoveFocus: () => {},
|
||||
onMoveSoftFocusToCurrentCell: () => {},
|
||||
onMoveHoverToCurrentCell: () => {},
|
||||
}}
|
||||
>
|
||||
{children}
|
||||
|
||||
Reference in New Issue
Block a user