Speed up RecordTableCell by 5x (#5023)
Improved table cell performances by putting all hooks from RecordTableCell in RecordTableContext and RecordTable component, so that each cell now only subscribes to a reference to those hooks' returned function. We couldn't do memoization here since the problem is not to memoize between re-renders but to share the same function reference between hundreds of different components, so a context it the fastest way for this. I had to refactor the hooks a little bit so that they take as arguments what was previously taken from the cell's context.
This commit is contained in:
@ -0,0 +1,57 @@
|
||||
import { isUndefined } from '@sniptt/guards';
|
||||
import { useRecoilCallback } from 'recoil';
|
||||
|
||||
import { recordFieldInputDraftValueComponentSelector } from '@/object-record/record-field/states/selectors/recordFieldInputDraftValueComponentSelector';
|
||||
import { FieldDefinition } from '@/object-record/record-field/types/FieldDefinition';
|
||||
import { FieldInputDraftValue } from '@/object-record/record-field/types/FieldInputDraftValue';
|
||||
import { FieldMetadata } from '@/object-record/record-field/types/FieldMetadata';
|
||||
import { computeDraftValueFromFieldValue } from '@/object-record/record-field/utils/computeDraftValueFromFieldValue';
|
||||
import { computeDraftValueFromString } from '@/object-record/record-field/utils/computeDraftValueFromString';
|
||||
import { recordStoreFamilySelector } from '@/object-record/record-store/states/selectors/recordStoreFamilySelector';
|
||||
import { extractComponentSelector } from '@/ui/utilities/state/component-state/utils/extractComponentSelector';
|
||||
|
||||
export const useInitDraftValueV2 = <FieldValue>() => {
|
||||
return useRecoilCallback(
|
||||
({ set, snapshot }) =>
|
||||
({
|
||||
value,
|
||||
entityId,
|
||||
fieldDefinition,
|
||||
}: {
|
||||
value?: string;
|
||||
entityId: string;
|
||||
fieldDefinition: FieldDefinition<FieldMetadata>;
|
||||
}) => {
|
||||
const recordFieldInputScopeId = `${entityId}-${fieldDefinition?.metadata?.fieldName}-scope`;
|
||||
|
||||
const getDraftValueSelector = extractComponentSelector<
|
||||
FieldInputDraftValue<FieldValue> | undefined
|
||||
>(recordFieldInputDraftValueComponentSelector, recordFieldInputScopeId);
|
||||
|
||||
const recordFieldValue = snapshot
|
||||
.getLoadable(
|
||||
recordStoreFamilySelector<FieldValue>({
|
||||
recordId: entityId,
|
||||
fieldName: fieldDefinition.metadata.fieldName,
|
||||
}),
|
||||
)
|
||||
.getValue();
|
||||
|
||||
if (isUndefined(value)) {
|
||||
set(
|
||||
getDraftValueSelector(),
|
||||
computeDraftValueFromFieldValue<FieldValue>({
|
||||
fieldValue: recordFieldValue,
|
||||
fieldDefinition,
|
||||
}),
|
||||
);
|
||||
} else {
|
||||
set(
|
||||
getDraftValueSelector(),
|
||||
computeDraftValueFromString<FieldValue>({ value, fieldDefinition }),
|
||||
);
|
||||
}
|
||||
},
|
||||
[],
|
||||
);
|
||||
};
|
||||
@ -7,8 +7,20 @@ import { RecordTableBody } from '@/object-record/record-table/components/RecordT
|
||||
import { RecordTableBodyEffect } from '@/object-record/record-table/components/RecordTableBodyEffect';
|
||||
import { RecordTableHeader } from '@/object-record/record-table/components/RecordTableHeader';
|
||||
import { RecordTableContext } from '@/object-record/record-table/contexts/RecordTableContext';
|
||||
import { useHandleContainerMouseEnter } from '@/object-record/record-table/hooks/internal/useHandleContainerMouseEnter';
|
||||
import { useRecordTableStates } from '@/object-record/record-table/hooks/internal/useRecordTableStates';
|
||||
import { useRecordTableMoveFocus } from '@/object-record/record-table/hooks/useRecordTableMoveFocus';
|
||||
import { useCloseRecordTableCellV2 } from '@/object-record/record-table/record-table-cell/hooks/useCloseRecordTableCellV2';
|
||||
import { useMoveSoftFocusToCellOnHoverV2 } from '@/object-record/record-table/record-table-cell/hooks/useMoveSoftFocusToCellOnHoverV2';
|
||||
import {
|
||||
OpenTableCellArgs,
|
||||
useOpenRecordTableCellV2,
|
||||
} from '@/object-record/record-table/record-table-cell/hooks/useOpenRecordTableCellV2';
|
||||
import { useTriggerContextMenu } from '@/object-record/record-table/record-table-cell/hooks/useTriggerContextMenu';
|
||||
import { useUpsertRecordV2 } from '@/object-record/record-table/record-table-cell/hooks/useUpsertRecordV2';
|
||||
import { RecordTableScope } from '@/object-record/record-table/scopes/RecordTableScope';
|
||||
import { MoveFocusDirection } from '@/object-record/record-table/types/MoveFocusDirection';
|
||||
import { TableCellPosition } from '@/object-record/record-table/types/TableCellPosition';
|
||||
import { MOBILE_VIEWPORT } from '@/ui/theme/constants/MobileViewport';
|
||||
import { RGBA } from '@/ui/theme/constants/Rgba';
|
||||
import { scrollLeftState } from '@/ui/utilities/scroll/states/scrollLeftState';
|
||||
@ -145,6 +157,59 @@ export const RecordTable = ({
|
||||
objectNameSingular,
|
||||
});
|
||||
|
||||
const { upsertRecord } = useUpsertRecordV2({
|
||||
objectNameSingular,
|
||||
});
|
||||
|
||||
const handleUpsertRecord = ({
|
||||
persistField,
|
||||
entityId,
|
||||
fieldName,
|
||||
}: {
|
||||
persistField: () => void;
|
||||
entityId: string;
|
||||
fieldName: string;
|
||||
}) => {
|
||||
upsertRecord(persistField, entityId, fieldName, recordTableId);
|
||||
};
|
||||
|
||||
const { openTableCell } = useOpenRecordTableCellV2(recordTableId);
|
||||
|
||||
const handleOpenTableCell = (args: OpenTableCellArgs) => {
|
||||
openTableCell(args);
|
||||
};
|
||||
|
||||
const { moveFocus } = useRecordTableMoveFocus(recordTableId);
|
||||
|
||||
const handleMoveFocus = (direction: MoveFocusDirection) => {
|
||||
moveFocus(direction);
|
||||
};
|
||||
|
||||
const { closeTableCell } = useCloseRecordTableCellV2(recordTableId);
|
||||
|
||||
const handleCloseTableCell = () => {
|
||||
closeTableCell();
|
||||
};
|
||||
|
||||
const { moveSoftFocusToCell } =
|
||||
useMoveSoftFocusToCellOnHoverV2(recordTableId);
|
||||
|
||||
const handleMoveSoftFocusToCell = (cellPosition: TableCellPosition) => {
|
||||
moveSoftFocusToCell(cellPosition);
|
||||
};
|
||||
|
||||
const { triggerContextMenu } = useTriggerContextMenu({
|
||||
recordTableId,
|
||||
});
|
||||
|
||||
const handleContextMenu = (event: React.MouseEvent, recordId: string) => {
|
||||
triggerContextMenu(event, recordId);
|
||||
};
|
||||
|
||||
const { handleContainerMouseEnter } = useHandleContainerMouseEnter({
|
||||
recordTableId,
|
||||
});
|
||||
|
||||
return (
|
||||
<RecordTableScope
|
||||
recordTableScopeId={scopeId}
|
||||
@ -154,6 +219,13 @@ export const RecordTable = ({
|
||||
<RecordTableContext.Provider
|
||||
value={{
|
||||
objectMetadataItem,
|
||||
onUpsertRecord: handleUpsertRecord,
|
||||
onOpenTableCell: handleOpenTableCell,
|
||||
onMoveFocus: handleMoveFocus,
|
||||
onCloseTableCell: handleCloseTableCell,
|
||||
onMoveSoftFocusToCell: handleMoveSoftFocusToCell,
|
||||
onContextMenu: handleContextMenu,
|
||||
onCellMouseEnter: handleContainerMouseEnter,
|
||||
}}
|
||||
>
|
||||
<StyledTable
|
||||
|
||||
@ -12,7 +12,7 @@ import { TableHotkeyScope } from '@/object-record/record-table/types/TableHotkey
|
||||
import { RelationPickerHotkeyScope } from '@/object-record/relation-picker/types/RelationPickerHotkeyScope';
|
||||
import { isUndefinedOrNull } from '~/utils/isUndefinedOrNull';
|
||||
|
||||
export const RecordTableCellContainer = () => {
|
||||
export const RecordTableCellFieldContextWrapper = () => {
|
||||
const { objectMetadataItem } = useContext(RecordTableContext);
|
||||
const { columnDefinition } = useContext(RecordTableCellContext);
|
||||
const { recordId, pathToShowPage } = useContext(RecordTableRowContext);
|
||||
@ -4,7 +4,7 @@ import styled from '@emotion/styled';
|
||||
import { useRecoilValue } from 'recoil';
|
||||
|
||||
import { getBasePathToShowPage } from '@/object-metadata/utils/getBasePathToShowPage';
|
||||
import { RecordTableCellContainer } from '@/object-record/record-table/components/RecordTableCellContainer';
|
||||
import { RecordTableCellFieldContextWrapper } from '@/object-record/record-table/components/RecordTableCellFieldContextWrapper';
|
||||
import { RecordTableCellContext } from '@/object-record/record-table/contexts/RecordTableCellContext';
|
||||
import { RecordTableContext } from '@/object-record/record-table/contexts/RecordTableContext';
|
||||
import { RecordTableRowContext } from '@/object-record/record-table/contexts/RecordTableRowContext';
|
||||
@ -67,7 +67,7 @@ export const RecordTableRow = ({ recordId, rowIndex }: RecordTableRowProps) => {
|
||||
}}
|
||||
key={column.fieldMetadataId}
|
||||
>
|
||||
<RecordTableCellContainer />
|
||||
<RecordTableCellFieldContextWrapper />
|
||||
</RecordTableCellContext.Provider>
|
||||
) : (
|
||||
<td key={column.fieldMetadataId}></td>
|
||||
|
||||
@ -1,9 +1,28 @@
|
||||
import { createContext } from 'react';
|
||||
|
||||
import { ObjectMetadataItem } from '@/object-metadata/types/ObjectMetadataItem';
|
||||
import { HandleContainerMouseEnterArgs } from '@/object-record/record-table/hooks/internal/useHandleContainerMouseEnter';
|
||||
import { OpenTableCellArgs } from '@/object-record/record-table/record-table-cell/hooks/useOpenRecordTableCellV2';
|
||||
import { MoveFocusDirection } from '@/object-record/record-table/types/MoveFocusDirection';
|
||||
import { TableCellPosition } from '@/object-record/record-table/types/TableCellPosition';
|
||||
|
||||
type RecordTableContextProps = {
|
||||
objectMetadataItem: ObjectMetadataItem;
|
||||
onUpsertRecord: ({
|
||||
persistField,
|
||||
entityId,
|
||||
fieldName,
|
||||
}: {
|
||||
persistField: () => void;
|
||||
entityId: string;
|
||||
fieldName: string;
|
||||
}) => void;
|
||||
onOpenTableCell: (args: OpenTableCellArgs) => void;
|
||||
onMoveFocus: (direction: MoveFocusDirection) => void;
|
||||
onCloseTableCell: () => void;
|
||||
onMoveSoftFocusToCell: (cellPosition: TableCellPosition) => void;
|
||||
onContextMenu: (event: React.MouseEvent, recordId: string) => void;
|
||||
onCellMouseEnter: (args: HandleContainerMouseEnterArgs) => void;
|
||||
};
|
||||
|
||||
export const RecordTableContext = createContext<RecordTableContextProps>(
|
||||
|
||||
@ -0,0 +1,68 @@
|
||||
import { useRecoilCallback } from 'recoil';
|
||||
|
||||
import { useMoveSoftFocusToCellOnHoverV2 } from '@/object-record/record-table/record-table-cell/hooks/useMoveSoftFocusToCellOnHoverV2';
|
||||
import { currentTableCellInEditModePositionComponentState } from '@/object-record/record-table/states/currentTableCellInEditModePositionComponentState';
|
||||
import { isSoftFocusUsingMouseState } from '@/object-record/record-table/states/isSoftFocusUsingMouseState';
|
||||
import { isTableCellInEditModeComponentFamilyState } from '@/object-record/record-table/states/isTableCellInEditModeComponentFamilyState';
|
||||
import { TableCellPosition } from '@/object-record/record-table/types/TableCellPosition';
|
||||
import { getScopeIdFromComponentId } from '@/ui/utilities/recoil-scope/utils/getScopeIdFromComponentId';
|
||||
import { getSnapshotValue } from '@/ui/utilities/recoil-scope/utils/getSnapshotValue';
|
||||
import { extractComponentFamilyState } from '@/ui/utilities/state/component-state/utils/extractComponentFamilyState';
|
||||
import { extractComponentState } from '@/ui/utilities/state/component-state/utils/extractComponentState';
|
||||
|
||||
export type HandleContainerMouseEnterArgs = {
|
||||
isHovered: boolean;
|
||||
setIsHovered: React.Dispatch<React.SetStateAction<boolean>>;
|
||||
cellPosition: TableCellPosition;
|
||||
};
|
||||
|
||||
export const useHandleContainerMouseEnter = ({
|
||||
recordTableId,
|
||||
}: {
|
||||
recordTableId: string;
|
||||
}) => {
|
||||
const tableScopeId = getScopeIdFromComponentId(recordTableId);
|
||||
|
||||
const { moveSoftFocusToCell } =
|
||||
useMoveSoftFocusToCellOnHoverV2(recordTableId);
|
||||
|
||||
const handleContainerMouseEnter = useRecoilCallback(
|
||||
({ snapshot, set }) =>
|
||||
({
|
||||
isHovered,
|
||||
setIsHovered,
|
||||
cellPosition,
|
||||
}: HandleContainerMouseEnterArgs) => {
|
||||
const currentTableCellInEditModePositionState = extractComponentState(
|
||||
currentTableCellInEditModePositionComponentState,
|
||||
tableScopeId,
|
||||
);
|
||||
|
||||
const currentTableCellInEditModePosition = getSnapshotValue(
|
||||
snapshot,
|
||||
currentTableCellInEditModePositionState,
|
||||
);
|
||||
|
||||
const isTableCellInEditModeFamilyState = extractComponentFamilyState(
|
||||
isTableCellInEditModeComponentFamilyState,
|
||||
tableScopeId,
|
||||
);
|
||||
|
||||
const isSomeCellInEditMode = getSnapshotValue(
|
||||
snapshot,
|
||||
isTableCellInEditModeFamilyState(currentTableCellInEditModePosition),
|
||||
);
|
||||
|
||||
if (!isHovered && !isSomeCellInEditMode) {
|
||||
setIsHovered(true);
|
||||
moveSoftFocusToCell(cellPosition);
|
||||
set(isSoftFocusUsingMouseState, true);
|
||||
}
|
||||
},
|
||||
[tableScopeId, moveSoftFocusToCell],
|
||||
);
|
||||
|
||||
return {
|
||||
handleContainerMouseEnter,
|
||||
};
|
||||
};
|
||||
@ -1,6 +1,7 @@
|
||||
import { useRecoilCallback } from 'recoil';
|
||||
|
||||
import { useRecordTableStates } from '@/object-record/record-table/hooks/internal/useRecordTableStates';
|
||||
import { MoveFocusDirection } from '@/object-record/record-table/types/MoveFocusDirection';
|
||||
import { getSnapshotValue } from '@/ui/utilities/recoil-scope/utils/getSnapshotValue';
|
||||
|
||||
import { useSetSoftFocusPosition } from './internal/useSetSoftFocusPosition';
|
||||
@ -167,6 +168,23 @@ export const useRecordTableMoveFocus = (recordTableId?: string) => {
|
||||
],
|
||||
);
|
||||
|
||||
const moveFocus = (direction: MoveFocusDirection) => {
|
||||
switch (direction) {
|
||||
case 'up':
|
||||
moveUp();
|
||||
break;
|
||||
case 'down':
|
||||
moveDown();
|
||||
break;
|
||||
case 'left':
|
||||
moveLeft();
|
||||
break;
|
||||
case 'right':
|
||||
moveRight();
|
||||
break;
|
||||
}
|
||||
};
|
||||
|
||||
return {
|
||||
scopeId,
|
||||
moveDown,
|
||||
@ -175,5 +193,6 @@ export const useRecordTableMoveFocus = (recordTableId?: string) => {
|
||||
moveUp,
|
||||
setSoftFocusPosition,
|
||||
selectedRowIdsSelector,
|
||||
moveFocus,
|
||||
};
|
||||
};
|
||||
|
||||
@ -4,11 +4,9 @@ import { FieldDisplay } from '@/object-record/record-field/components/FieldDispl
|
||||
import { FieldInput } from '@/object-record/record-field/components/FieldInput';
|
||||
import { FieldContext } from '@/object-record/record-field/contexts/FieldContext';
|
||||
import { FieldInputEvent } from '@/object-record/record-field/types/FieldInputEvent';
|
||||
import { RecordTableContext } from '@/object-record/record-table/contexts/RecordTableContext';
|
||||
import { RecordTableRowContext } from '@/object-record/record-table/contexts/RecordTableRowContext';
|
||||
import { useRecordTableMoveFocus } from '@/object-record/record-table/hooks/useRecordTableMoveFocus';
|
||||
import { RecordTableCellContainer } from '@/object-record/record-table/record-table-cell/components/RecordTableCellContainer';
|
||||
import { useCloseRecordTableCell } from '@/object-record/record-table/record-table-cell/hooks/useCloseRecordTableCell';
|
||||
import { useUpsertRecord } from '@/object-record/record-table/record-table-cell/hooks/useUpsertRecord';
|
||||
import { HotkeyScope } from '@/ui/utilities/hotkey/types/HotkeyScope';
|
||||
|
||||
export const RecordTableCell = ({
|
||||
@ -16,55 +14,76 @@ export const RecordTableCell = ({
|
||||
}: {
|
||||
customHotkeyScope: HotkeyScope;
|
||||
}) => {
|
||||
const { closeTableCell } = useCloseRecordTableCell();
|
||||
const { upsertRecord } = useUpsertRecord();
|
||||
|
||||
const { moveLeft, moveRight, moveDown } = useRecordTableMoveFocus();
|
||||
|
||||
const { onUpsertRecord, onMoveFocus, onCloseTableCell } =
|
||||
useContext(RecordTableContext);
|
||||
const { entityId, fieldDefinition } = useContext(FieldContext);
|
||||
const { isReadOnly } = useContext(RecordTableRowContext);
|
||||
|
||||
const handleEnter: FieldInputEvent = (persistField) => {
|
||||
upsertRecord(persistField);
|
||||
onUpsertRecord({
|
||||
persistField,
|
||||
entityId,
|
||||
fieldName: fieldDefinition.metadata.fieldName,
|
||||
});
|
||||
|
||||
closeTableCell();
|
||||
moveDown();
|
||||
onCloseTableCell();
|
||||
onMoveFocus('down');
|
||||
};
|
||||
|
||||
const handleSubmit: FieldInputEvent = (persistField) => {
|
||||
upsertRecord(persistField);
|
||||
onUpsertRecord({
|
||||
persistField,
|
||||
entityId,
|
||||
fieldName: fieldDefinition.metadata.fieldName,
|
||||
});
|
||||
|
||||
closeTableCell();
|
||||
onCloseTableCell();
|
||||
};
|
||||
|
||||
const handleCancel = () => {
|
||||
closeTableCell();
|
||||
onCloseTableCell();
|
||||
};
|
||||
|
||||
const handleClickOutside: FieldInputEvent = (persistField) => {
|
||||
upsertRecord(persistField);
|
||||
onUpsertRecord({
|
||||
persistField,
|
||||
entityId,
|
||||
fieldName: fieldDefinition.metadata.fieldName,
|
||||
});
|
||||
|
||||
closeTableCell();
|
||||
onCloseTableCell();
|
||||
};
|
||||
|
||||
const handleEscape: FieldInputEvent = (persistField) => {
|
||||
upsertRecord(persistField);
|
||||
onUpsertRecord({
|
||||
persistField,
|
||||
entityId,
|
||||
fieldName: fieldDefinition.metadata.fieldName,
|
||||
});
|
||||
|
||||
closeTableCell();
|
||||
onCloseTableCell();
|
||||
};
|
||||
|
||||
const handleTab: FieldInputEvent = (persistField) => {
|
||||
upsertRecord(persistField);
|
||||
onUpsertRecord({
|
||||
persistField,
|
||||
entityId,
|
||||
fieldName: fieldDefinition.metadata.fieldName,
|
||||
});
|
||||
|
||||
closeTableCell();
|
||||
moveRight();
|
||||
onCloseTableCell();
|
||||
onMoveFocus('right');
|
||||
};
|
||||
|
||||
const handleShiftTab: FieldInputEvent = (persistField) => {
|
||||
upsertRecord(persistField);
|
||||
onUpsertRecord({
|
||||
persistField,
|
||||
entityId,
|
||||
fieldName: fieldDefinition.metadata.fieldName,
|
||||
});
|
||||
|
||||
closeTableCell();
|
||||
moveLeft();
|
||||
onCloseTableCell();
|
||||
onMoveFocus('left');
|
||||
};
|
||||
|
||||
return (
|
||||
|
||||
@ -1,28 +1,26 @@
|
||||
import { ReactElement, useContext, useState } from 'react';
|
||||
import React, { ReactElement, useContext, useState } from 'react';
|
||||
import styled from '@emotion/styled';
|
||||
import { useRecoilCallback, useSetRecoilState } from 'recoil';
|
||||
import { useRecoilValue } from 'recoil';
|
||||
import { IconArrowUpRight } from 'twenty-ui';
|
||||
|
||||
import { useGetButtonIcon } from '@/object-record/record-field/hooks/useGetButtonIcon';
|
||||
import { useIsFieldEmpty } from '@/object-record/record-field/hooks/useIsFieldEmpty';
|
||||
import { useIsFieldInputOnly } from '@/object-record/record-field/hooks/useIsFieldInputOnly';
|
||||
import { RecordTableCellContext } from '@/object-record/record-table/contexts/RecordTableCellContext';
|
||||
import { RecordTableContext } from '@/object-record/record-table/contexts/RecordTableContext';
|
||||
import { RecordTableRowContext } from '@/object-record/record-table/contexts/RecordTableRowContext';
|
||||
import { useGetIsSomeCellInEditModeState } from '@/object-record/record-table/hooks/internal/useGetIsSomeCellInEditMode';
|
||||
import { useOpenRecordTableCell } from '@/object-record/record-table/record-table-cell/hooks/useOpenRecordTableCell';
|
||||
import { useSetCurrentRowSelected } from '@/object-record/record-table/record-table-row/hooks/useSetCurrentRowSelected';
|
||||
import { isSoftFocusUsingMouseState } from '@/object-record/record-table/states/isSoftFocusUsingMouseState';
|
||||
import { contextMenuIsOpenState } from '@/ui/navigation/context-menu/states/contextMenuIsOpenState';
|
||||
import { contextMenuPositionState } from '@/ui/navigation/context-menu/states/contextMenuPositionState';
|
||||
import { useCurrentTableCellPosition } from '@/object-record/record-table/record-table-cell/hooks/useCurrentCellPosition';
|
||||
import { useOpenRecordTableCellFromCell } from '@/object-record/record-table/record-table-cell/hooks/useOpenRecordTableCellFromCell';
|
||||
import { RecordTableScopeInternalContext } from '@/object-record/record-table/scopes/scope-internal-context/RecordTableScopeInternalContext';
|
||||
import { isSoftFocusOnTableCellComponentFamilyState } from '@/object-record/record-table/states/isSoftFocusOnTableCellComponentFamilyState';
|
||||
import { isTableCellInEditModeComponentFamilyState } from '@/object-record/record-table/states/isTableCellInEditModeComponentFamilyState';
|
||||
import { HotkeyScope } from '@/ui/utilities/hotkey/types/HotkeyScope';
|
||||
import { getSnapshotValue } from '@/ui/utilities/recoil-scope/utils/getSnapshotValue';
|
||||
import { useAvailableScopeIdOrThrow } from '@/ui/utilities/recoil-scope/scopes-internal/hooks/useAvailableScopeId';
|
||||
import { getScopeIdOrUndefinedFromComponentId } from '@/ui/utilities/recoil-scope/utils/getScopeIdOrUndefinedFromComponentId';
|
||||
import { extractComponentFamilyState } from '@/ui/utilities/state/component-state/utils/extractComponentFamilyState';
|
||||
|
||||
import { CellHotkeyScopeContext } from '../../contexts/CellHotkeyScopeContext';
|
||||
import { TableHotkeyScope } from '../../types/TableHotkeyScope';
|
||||
import { useCurrentTableCellEditMode } from '../hooks/useCurrentTableCellEditMode';
|
||||
import { useIsSoftFocusOnCurrentTableCell } from '../hooks/useIsSoftFocusOnCurrentTableCell';
|
||||
import { useMoveSoftFocusToCurrentCellOnHover } from '../hooks/useMoveSoftFocusToCurrentCellOnHover';
|
||||
import { useSetSoftFocusOnCurrentTableCell } from '../hooks/useSetSoftFocusOnCurrentTableCell';
|
||||
|
||||
import { RecordTableCellButton } from './RecordTableCellButton';
|
||||
import { RecordTableCellDisplayMode } from './RecordTableCellDisplayMode';
|
||||
@ -64,65 +62,60 @@ export const RecordTableCellContainer = ({
|
||||
nonEditModeContent,
|
||||
editHotkeyScope,
|
||||
}: RecordTableCellContainerProps) => {
|
||||
const { columnIndex } = useContext(RecordTableCellContext);
|
||||
const { isReadOnly, isSelected, recordId } = useContext(
|
||||
RecordTableRowContext,
|
||||
);
|
||||
const { onMoveSoftFocusToCell, onContextMenu, onCellMouseEnter } =
|
||||
useContext(RecordTableContext);
|
||||
|
||||
const cellPosition = useCurrentTableCellPosition();
|
||||
|
||||
const [isHovered, setIsHovered] = useState(false);
|
||||
|
||||
const { isCurrentTableCellInEditMode } = useCurrentTableCellEditMode();
|
||||
const isSomeCellInEditModeState = useGetIsSomeCellInEditModeState();
|
||||
const { openTableCell } = useOpenRecordTableCellFromCell();
|
||||
|
||||
const setIsSoftFocusUsingMouseState = useSetRecoilState(
|
||||
isSoftFocusUsingMouseState,
|
||||
const tableScopeId = useAvailableScopeIdOrThrow(
|
||||
RecordTableScopeInternalContext,
|
||||
getScopeIdOrUndefinedFromComponentId(),
|
||||
);
|
||||
|
||||
const moveSoftFocusToCurrentCellOnHover =
|
||||
useMoveSoftFocusToCurrentCellOnHover();
|
||||
const isTableCellInEditModeFamilyState = extractComponentFamilyState(
|
||||
isTableCellInEditModeComponentFamilyState,
|
||||
tableScopeId,
|
||||
);
|
||||
|
||||
const hasSoftFocus = useIsSoftFocusOnCurrentTableCell();
|
||||
const setSoftFocusOnCurrentTableCell = useSetSoftFocusOnCurrentTableCell();
|
||||
const isSoftFocusOnTableCellFamilyState = extractComponentFamilyState(
|
||||
isSoftFocusOnTableCellComponentFamilyState,
|
||||
tableScopeId,
|
||||
);
|
||||
|
||||
const { openTableCell } = useOpenRecordTableCell();
|
||||
const isCurrentTableCellInEditMode = useRecoilValue(
|
||||
isTableCellInEditModeFamilyState(cellPosition),
|
||||
);
|
||||
|
||||
const hasSoftFocus = useRecoilValue(
|
||||
isSoftFocusOnTableCellFamilyState(cellPosition),
|
||||
);
|
||||
|
||||
const isEmpty = useIsFieldEmpty();
|
||||
|
||||
const handleButtonClick = () => {
|
||||
setSoftFocusOnCurrentTableCell();
|
||||
onMoveSoftFocusToCell(cellPosition);
|
||||
openTableCell();
|
||||
};
|
||||
|
||||
const { isSelected, isReadOnly } = useContext(RecordTableRowContext);
|
||||
|
||||
const setContextMenuPosition = useSetRecoilState(contextMenuPositionState);
|
||||
const setContextMenuOpenState = useSetRecoilState(contextMenuIsOpenState);
|
||||
|
||||
const { setCurrentRowSelected } = useSetCurrentRowSelected();
|
||||
|
||||
const handleContextMenu = (event: React.MouseEvent) => {
|
||||
event.preventDefault();
|
||||
setCurrentRowSelected(true);
|
||||
setContextMenuPosition({
|
||||
x: event.clientX,
|
||||
y: event.clientY,
|
||||
});
|
||||
setContextMenuOpenState(true);
|
||||
onContextMenu(event, recordId);
|
||||
};
|
||||
|
||||
const handleContainerMouseEnter = useRecoilCallback(
|
||||
({ snapshot }) =>
|
||||
() => {
|
||||
const isSomeCellInEditMode = getSnapshotValue(
|
||||
snapshot,
|
||||
isSomeCellInEditModeState(),
|
||||
);
|
||||
if (!isHovered && !isSomeCellInEditMode) {
|
||||
setIsHovered(true);
|
||||
moveSoftFocusToCurrentCellOnHover();
|
||||
setIsSoftFocusUsingMouseState(true);
|
||||
}
|
||||
},
|
||||
[
|
||||
const handleContainerMouseEnter = () => {
|
||||
onCellMouseEnter({
|
||||
cellPosition,
|
||||
isHovered,
|
||||
isSomeCellInEditModeState,
|
||||
moveSoftFocusToCurrentCellOnHover,
|
||||
setIsSoftFocusUsingMouseState,
|
||||
],
|
||||
);
|
||||
setIsHovered,
|
||||
});
|
||||
};
|
||||
|
||||
const handleContainerMouseLeave = () => {
|
||||
setIsHovered(false);
|
||||
@ -130,9 +123,6 @@ export const RecordTableCellContainer = ({
|
||||
|
||||
const editModeContentOnly = useIsFieldInputOnly();
|
||||
|
||||
const isEmpty = useIsFieldEmpty();
|
||||
|
||||
const { columnIndex } = useContext(RecordTableCellContext);
|
||||
const isFirstColumn = columnIndex === 0;
|
||||
const customButtonIcon = useGetButtonIcon();
|
||||
const buttonIcon = isFirstColumn ? IconArrowUpRight : customButtonIcon;
|
||||
@ -148,7 +138,7 @@ export const RecordTableCellContainer = ({
|
||||
return (
|
||||
<StyledTd
|
||||
isSelected={isSelected}
|
||||
onContextMenu={(event) => handleContextMenu(event)}
|
||||
onContextMenu={handleContextMenu}
|
||||
isInEditMode={isCurrentTableCellInEditMode}
|
||||
>
|
||||
<CellHotkeyScopeContext.Provider
|
||||
@ -180,9 +170,11 @@ export const RecordTableCellContainer = ({
|
||||
Icon={buttonIcon}
|
||||
/>
|
||||
)}
|
||||
<RecordTableCellDisplayMode>
|
||||
{editModeContentOnly ? editModeContent : nonEditModeContent}
|
||||
</RecordTableCellDisplayMode>
|
||||
{!isEmpty && (
|
||||
<RecordTableCellDisplayMode>
|
||||
{editModeContentOnly ? editModeContent : nonEditModeContent}
|
||||
</RecordTableCellDisplayMode>
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
</StyledCellBaseContainer>
|
||||
|
||||
@ -1,21 +1,23 @@
|
||||
import { useIsFieldInputOnly } from '@/object-record/record-field/hooks/useIsFieldInputOnly';
|
||||
import { useOpenRecordTableCell } from '@/object-record/record-table/record-table-cell/hooks/useOpenRecordTableCell';
|
||||
import { useContext } from 'react';
|
||||
|
||||
import { useSetSoftFocusOnCurrentTableCell } from '../hooks/useSetSoftFocusOnCurrentTableCell';
|
||||
import { useIsFieldInputOnly } from '@/object-record/record-field/hooks/useIsFieldInputOnly';
|
||||
import { RecordTableContext } from '@/object-record/record-table/contexts/RecordTableContext';
|
||||
import { useCurrentTableCellPosition } from '@/object-record/record-table/record-table-cell/hooks/useCurrentCellPosition';
|
||||
import { useOpenRecordTableCellFromCell } from '@/object-record/record-table/record-table-cell/hooks/useOpenRecordTableCellFromCell';
|
||||
|
||||
import { RecordTableCellDisplayContainer } from './RecordTableCellDisplayContainer';
|
||||
|
||||
export const RecordTableCellDisplayMode = ({
|
||||
children,
|
||||
}: React.PropsWithChildren<unknown>) => {
|
||||
const setSoftFocusOnCurrentCell = useSetSoftFocusOnCurrentTableCell();
|
||||
const cellPosition = useCurrentTableCellPosition();
|
||||
const { onMoveSoftFocusToCell } = useContext(RecordTableContext);
|
||||
const { openTableCell } = useOpenRecordTableCellFromCell();
|
||||
|
||||
const isFieldInputOnly = useIsFieldInputOnly();
|
||||
|
||||
const { openTableCell } = useOpenRecordTableCell();
|
||||
|
||||
const handleClick = () => {
|
||||
setSoftFocusOnCurrentCell();
|
||||
onMoveSoftFocusToCell(cellPosition);
|
||||
|
||||
if (!isFieldInputOnly) {
|
||||
openTableCell();
|
||||
|
||||
@ -6,7 +6,7 @@ import { useClearField } from '@/object-record/record-field/hooks/useClearField'
|
||||
import { useIsFieldClearable } from '@/object-record/record-field/hooks/useIsFieldClearable';
|
||||
import { useIsFieldInputOnly } from '@/object-record/record-field/hooks/useIsFieldInputOnly';
|
||||
import { useToggleEditOnlyInput } from '@/object-record/record-field/hooks/useToggleEditOnlyInput';
|
||||
import { useOpenRecordTableCell } from '@/object-record/record-table/record-table-cell/hooks/useOpenRecordTableCell';
|
||||
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';
|
||||
@ -20,7 +20,7 @@ type RecordTableCellSoftFocusModeProps = PropsWithChildren<unknown>;
|
||||
export const RecordTableCellSoftFocusMode = ({
|
||||
children,
|
||||
}: RecordTableCellSoftFocusModeProps) => {
|
||||
const { openTableCell } = useOpenRecordTableCell();
|
||||
const { openTableCell } = useOpenRecordTableCellFromCell();
|
||||
|
||||
const isFieldInputOnly = useIsFieldInputOnly();
|
||||
|
||||
@ -82,9 +82,7 @@ export const RecordTableCellSoftFocusMode = ({
|
||||
keyboardEvent.stopPropagation();
|
||||
keyboardEvent.stopImmediatePropagation();
|
||||
|
||||
openTableCell({
|
||||
initialValue: keyboardEvent.key,
|
||||
});
|
||||
openTableCell(keyboardEvent.key);
|
||||
}
|
||||
},
|
||||
TableHotkeyScope.TableSoftFocus,
|
||||
|
||||
@ -0,0 +1,38 @@
|
||||
import { useResetRecoilState } from 'recoil';
|
||||
|
||||
import { SOFT_FOCUS_CLICK_OUTSIDE_LISTENER_ID } from '@/object-record/record-table/constants/SoftFocusClickOutsideListenerId';
|
||||
import { useRecordTableStates } from '@/object-record/record-table/hooks/internal/useRecordTableStates';
|
||||
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';
|
||||
|
||||
import { useCloseCurrentTableCellInEditMode } from '../../hooks/internal/useCloseCurrentTableCellInEditMode';
|
||||
import { TableHotkeyScope } from '../../types/TableHotkeyScope';
|
||||
|
||||
export const useCloseRecordTableCellV2 = (recordTableScopeId: string) => {
|
||||
const setHotkeyScope = useSetHotkeyScope();
|
||||
const { setDragSelectionStartEnabled } = useDragSelect();
|
||||
const { pendingRecordIdState } = useRecordTableStates(recordTableScopeId);
|
||||
|
||||
const { toggleClickOutsideListener } = useClickOutsideListener(
|
||||
SOFT_FOCUS_CLICK_OUTSIDE_LISTENER_ID,
|
||||
);
|
||||
|
||||
const closeCurrentTableCellInEditMode =
|
||||
useCloseCurrentTableCellInEditMode(recordTableScopeId);
|
||||
|
||||
const resetRecordTablePendingRecordId =
|
||||
useResetRecoilState(pendingRecordIdState);
|
||||
|
||||
const closeTableCell = async () => {
|
||||
toggleClickOutsideListener(true);
|
||||
setDragSelectionStartEnabled(true);
|
||||
closeCurrentTableCellInEditMode();
|
||||
setHotkeyScope(TableHotkeyScope.TableSoftFocus);
|
||||
resetRecordTablePendingRecordId();
|
||||
};
|
||||
|
||||
return {
|
||||
closeTableCell,
|
||||
};
|
||||
};
|
||||
@ -0,0 +1,59 @@
|
||||
import { useRecoilCallback } from 'recoil';
|
||||
|
||||
import { useRecordTableStates } from '@/object-record/record-table/hooks/internal/useRecordTableStates';
|
||||
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 { TableHotkeyScope } from '../../types/TableHotkeyScope';
|
||||
|
||||
export const useMoveSoftFocusToCellOnHoverV2 = (recordTableId: string) => {
|
||||
const setSoftFocus = useSetSoftFocus(recordTableId);
|
||||
|
||||
const {
|
||||
currentTableCellInEditModePositionState,
|
||||
isTableCellInEditModeFamilyState,
|
||||
} = useRecordTableStates(recordTableId);
|
||||
|
||||
const moveSoftFocusToCell = 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
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!isSomeCellInEditMode) {
|
||||
setSoftFocus(cellPosition);
|
||||
}
|
||||
},
|
||||
[
|
||||
currentTableCellInEditModePositionState,
|
||||
isTableCellInEditModeFamilyState,
|
||||
setSoftFocus,
|
||||
],
|
||||
);
|
||||
|
||||
return { moveSoftFocusToCell };
|
||||
};
|
||||
@ -0,0 +1,51 @@
|
||||
import { useContext } from 'react';
|
||||
|
||||
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 { CellHotkeyScopeContext } from '@/object-record/record-table/contexts/CellHotkeyScopeContext';
|
||||
import { RecordTableContext } from '@/object-record/record-table/contexts/RecordTableContext';
|
||||
import { RecordTableRowContext } 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 { TableHotkeyScope } from '../../types/TableHotkeyScope';
|
||||
|
||||
export const DEFAULT_CELL_SCOPE: HotkeyScope = {
|
||||
scope: TableHotkeyScope.CellEditMode,
|
||||
};
|
||||
|
||||
export type OpenTableCellArgs = {
|
||||
initialValue?: string;
|
||||
cellPosition: TableCellPosition;
|
||||
isReadOnly: boolean;
|
||||
pathToShowPage: string;
|
||||
customCellHotkeyScope: HotkeyScope | null;
|
||||
fieldDefinition: FieldDefinition<FieldMetadata>;
|
||||
entityId: string;
|
||||
};
|
||||
|
||||
export const useOpenRecordTableCellFromCell = () => {
|
||||
const { onOpenTableCell } = useContext(RecordTableContext);
|
||||
const cellPosition = useCurrentTableCellPosition();
|
||||
const customCellHotkeyScope = useContext(CellHotkeyScopeContext);
|
||||
const { entityId, fieldDefinition } = useContext(FieldContext);
|
||||
const { isReadOnly, pathToShowPage } = useContext(RecordTableRowContext);
|
||||
|
||||
const openTableCell = (initialValue?: string) => {
|
||||
onOpenTableCell({
|
||||
cellPosition,
|
||||
customCellHotkeyScope,
|
||||
entityId,
|
||||
fieldDefinition,
|
||||
isReadOnly,
|
||||
pathToShowPage,
|
||||
initialValue,
|
||||
});
|
||||
};
|
||||
|
||||
return {
|
||||
openTableCell,
|
||||
};
|
||||
};
|
||||
@ -0,0 +1,125 @@
|
||||
import { useNavigate } from 'react-router-dom';
|
||||
import { useRecoilCallback } from 'recoil';
|
||||
|
||||
import { useInitDraftValueV2 } from '@/object-record/record-field/hooks/useInitDraftValueV2';
|
||||
import { FieldDefinition } from '@/object-record/record-field/types/FieldDefinition';
|
||||
import { FieldMetadata } from '@/object-record/record-field/types/FieldMetadata';
|
||||
import { isFieldValueEmpty } from '@/object-record/record-field/utils/isFieldValueEmpty';
|
||||
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 { 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 { useSetHotkeyScope } from '@/ui/utilities/hotkey/hooks/useSetHotkeyScope';
|
||||
import { HotkeyScope } from '@/ui/utilities/hotkey/types/HotkeyScope';
|
||||
import { useClickOutsideListener } from '@/ui/utilities/pointer-event/hooks/useClickOutsideListener';
|
||||
import { getSnapshotValue } from '@/ui/utilities/state/utils/getSnapshotValue';
|
||||
import { isDefined } from '~/utils/isDefined';
|
||||
|
||||
import { TableHotkeyScope } from '../../types/TableHotkeyScope';
|
||||
|
||||
export const DEFAULT_CELL_SCOPE: HotkeyScope = {
|
||||
scope: TableHotkeyScope.CellEditMode,
|
||||
};
|
||||
|
||||
export type OpenTableCellArgs = {
|
||||
initialValue?: string;
|
||||
cellPosition: TableCellPosition;
|
||||
isReadOnly: boolean;
|
||||
pathToShowPage: string;
|
||||
customCellHotkeyScope: HotkeyScope | null;
|
||||
fieldDefinition: FieldDefinition<FieldMetadata>;
|
||||
entityId: string;
|
||||
};
|
||||
|
||||
export const useOpenRecordTableCellV2 = (tableScopeId: string) => {
|
||||
const moveEditModeToTableCellPosition =
|
||||
useMoveEditModeToTableCellPosition(tableScopeId);
|
||||
|
||||
const setHotkeyScope = useSetHotkeyScope();
|
||||
const { setDragSelectionStartEnabled } = useDragSelect();
|
||||
|
||||
const navigate = useNavigate();
|
||||
const leaveTableFocus = useLeaveTableFocus(tableScopeId);
|
||||
const { toggleClickOutsideListener } = useClickOutsideListener(
|
||||
SOFT_FOCUS_CLICK_OUTSIDE_LISTENER_ID,
|
||||
);
|
||||
|
||||
const initDraftValue = useInitDraftValueV2();
|
||||
|
||||
const openTableCell = useRecoilCallback(
|
||||
({ snapshot }) =>
|
||||
({
|
||||
initialValue,
|
||||
cellPosition,
|
||||
isReadOnly,
|
||||
pathToShowPage,
|
||||
customCellHotkeyScope,
|
||||
fieldDefinition,
|
||||
entityId,
|
||||
}: OpenTableCellArgs) => {
|
||||
if (isReadOnly) {
|
||||
return;
|
||||
}
|
||||
|
||||
const isFirstColumnCell = cellPosition.column === 0;
|
||||
|
||||
const fieldValue = getSnapshotValue(
|
||||
snapshot,
|
||||
recordStoreFamilySelector({
|
||||
recordId: entityId,
|
||||
fieldName: fieldDefinition.metadata.fieldName,
|
||||
}),
|
||||
);
|
||||
|
||||
const isEmpty = isFieldValueEmpty({
|
||||
fieldDefinition,
|
||||
fieldValue,
|
||||
});
|
||||
|
||||
if (isFirstColumnCell && !isEmpty) {
|
||||
leaveTableFocus();
|
||||
navigate(pathToShowPage);
|
||||
return;
|
||||
}
|
||||
|
||||
setDragSelectionStartEnabled(false);
|
||||
|
||||
moveEditModeToTableCellPosition(cellPosition);
|
||||
|
||||
initDraftValue({
|
||||
value: initialValue,
|
||||
entityId,
|
||||
fieldDefinition,
|
||||
});
|
||||
|
||||
toggleClickOutsideListener(false);
|
||||
|
||||
if (isDefined(customCellHotkeyScope)) {
|
||||
setHotkeyScope(
|
||||
customCellHotkeyScope.scope,
|
||||
customCellHotkeyScope.customScopes,
|
||||
);
|
||||
} else {
|
||||
setHotkeyScope(
|
||||
DEFAULT_CELL_SCOPE.scope,
|
||||
DEFAULT_CELL_SCOPE.customScopes,
|
||||
);
|
||||
}
|
||||
},
|
||||
[
|
||||
setDragSelectionStartEnabled,
|
||||
toggleClickOutsideListener,
|
||||
leaveTableFocus,
|
||||
navigate,
|
||||
setHotkeyScope,
|
||||
initDraftValue,
|
||||
moveEditModeToTableCellPosition,
|
||||
],
|
||||
);
|
||||
|
||||
return {
|
||||
openTableCell,
|
||||
};
|
||||
};
|
||||
@ -7,10 +7,10 @@ import { useSetHotkeyScope } from '@/ui/utilities/hotkey/hooks/useSetHotkeyScope
|
||||
|
||||
import { TableHotkeyScope } from '../../types/TableHotkeyScope';
|
||||
|
||||
export const useSetSoftFocus = () => {
|
||||
const setSoftFocusPosition = useSetSoftFocusPosition();
|
||||
export const useSetSoftFocus = (recordTableId?: string) => {
|
||||
const setSoftFocusPosition = useSetSoftFocusPosition(recordTableId);
|
||||
|
||||
const { isSoftFocusActiveState } = useRecordTableStates();
|
||||
const { isSoftFocusActiveState } = useRecordTableStates(recordTableId);
|
||||
|
||||
const setHotkeyScope = useSetHotkeyScope();
|
||||
|
||||
|
||||
@ -0,0 +1,46 @@
|
||||
import { useRecoilCallback } from 'recoil';
|
||||
|
||||
import { isRowSelectedComponentFamilyState } from '@/object-record/record-table/record-table-row/states/isRowSelectedComponentFamilyState';
|
||||
import { contextMenuIsOpenState } from '@/ui/navigation/context-menu/states/contextMenuIsOpenState';
|
||||
import { contextMenuPositionState } from '@/ui/navigation/context-menu/states/contextMenuPositionState';
|
||||
import { getScopeIdFromComponentId } from '@/ui/utilities/recoil-scope/utils/getScopeIdFromComponentId';
|
||||
import { getSnapshotValue } from '@/ui/utilities/recoil-scope/utils/getSnapshotValue';
|
||||
import { extractComponentFamilyState } from '@/ui/utilities/state/component-state/utils/extractComponentFamilyState';
|
||||
|
||||
export const useTriggerContextMenu = ({
|
||||
recordTableId,
|
||||
}: {
|
||||
recordTableId: string;
|
||||
}) => {
|
||||
const triggerContextMenu = useRecoilCallback(
|
||||
({ set, snapshot }) =>
|
||||
(event: React.MouseEvent, recordId: string) => {
|
||||
event.preventDefault();
|
||||
|
||||
const tableScopeId = getScopeIdFromComponentId(recordTableId);
|
||||
|
||||
set(contextMenuPositionState, {
|
||||
x: event.clientX,
|
||||
y: event.clientY,
|
||||
});
|
||||
set(contextMenuIsOpenState, true);
|
||||
|
||||
const isRowSelectedFamilyState = extractComponentFamilyState(
|
||||
isRowSelectedComponentFamilyState,
|
||||
tableScopeId,
|
||||
);
|
||||
|
||||
const isRowSelected = getSnapshotValue(
|
||||
snapshot,
|
||||
isRowSelectedFamilyState(recordId),
|
||||
);
|
||||
|
||||
if (isRowSelected !== true) {
|
||||
set(isRowSelectedFamilyState(recordId), true);
|
||||
}
|
||||
},
|
||||
[recordTableId],
|
||||
);
|
||||
|
||||
return { triggerContextMenu };
|
||||
};
|
||||
@ -0,0 +1,60 @@
|
||||
import { useRecoilCallback } from 'recoil';
|
||||
|
||||
import { useCreateOneRecord } from '@/object-record/hooks/useCreateOneRecord';
|
||||
import { recordFieldInputDraftValueComponentSelector } from '@/object-record/record-field/states/selectors/recordFieldInputDraftValueComponentSelector';
|
||||
import { recordTablePendingRecordIdComponentState } from '@/object-record/record-table/states/recordTablePendingRecordIdComponentState';
|
||||
import { getSnapshotValue } from '@/ui/utilities/recoil-scope/utils/getSnapshotValue';
|
||||
import { extractComponentSelector } from '@/ui/utilities/state/component-state/utils/extractComponentSelector';
|
||||
import { extractComponentState } from '@/ui/utilities/state/component-state/utils/extractComponentState';
|
||||
import { isDefined } from '~/utils/isDefined';
|
||||
|
||||
export const useUpsertRecordV2 = ({
|
||||
objectNameSingular,
|
||||
}: {
|
||||
objectNameSingular: string;
|
||||
}) => {
|
||||
const { createOneRecord } = useCreateOneRecord({
|
||||
objectNameSingular,
|
||||
});
|
||||
|
||||
const upsertRecord = useRecoilCallback(
|
||||
({ snapshot }) =>
|
||||
(
|
||||
persistField: () => void,
|
||||
entityId: string,
|
||||
fieldName: string,
|
||||
tableScopeId: string,
|
||||
) => {
|
||||
const recordTablePendingRecordIdState = extractComponentState(
|
||||
recordTablePendingRecordIdComponentState,
|
||||
tableScopeId,
|
||||
);
|
||||
|
||||
const recordTablePendingRecordId = getSnapshotValue(
|
||||
snapshot,
|
||||
recordTablePendingRecordIdState,
|
||||
);
|
||||
const fieldScopeId = `${entityId}-${fieldName}`;
|
||||
|
||||
const draftValueSelector = extractComponentSelector(
|
||||
recordFieldInputDraftValueComponentSelector,
|
||||
fieldScopeId,
|
||||
);
|
||||
|
||||
const draftValue = getSnapshotValue(snapshot, draftValueSelector());
|
||||
|
||||
if (isDefined(recordTablePendingRecordId) && isDefined(draftValue)) {
|
||||
createOneRecord({
|
||||
id: recordTablePendingRecordId,
|
||||
name: draftValue,
|
||||
position: 'first',
|
||||
});
|
||||
} else if (!recordTablePendingRecordId) {
|
||||
persistField();
|
||||
}
|
||||
},
|
||||
[createOneRecord],
|
||||
);
|
||||
|
||||
return { upsertRecord };
|
||||
};
|
||||
@ -0,0 +1 @@
|
||||
export type MoveFocusDirection = 'up' | 'down' | 'left' | 'right';
|
||||
Reference in New Issue
Block a user