Refactor board inline-cell input (#13928)

Makes board use the Input portals for Inline Cells
This commit is contained in:
Charles Bochet
2025-08-14 17:43:27 +02:00
committed by GitHub
parent 1707e00ad4
commit 5c61daa201
28 changed files with 583 additions and 190 deletions
@@ -10,6 +10,7 @@ import { useRecordTitleCell } from '@/object-record/record-title-cell/hooks/useR
import { RecordTitleCellContainerType } from '@/object-record/record-title-cell/types/RecordTitleCellContainerType';
import { type ObjectRecord } from '@/object-record/types/ObjectRecord';
import { getForeignKeyNameFromRelationFieldName } from '@/object-record/utils/getForeignKeyNameFromRelationFieldName';
import { getRecordFieldInputInstanceId } from '@/object-record/utils/getRecordFieldInputId';
import { isDefined } from 'twenty-shared/utils';
interface CreateRelatedRecordActionProps {
@@ -106,7 +107,11 @@ export const CreateRelatedRecordAction = ({
openRecordTitleCell({
recordId: createdRecord.id,
fieldName: labelIdentifierFieldMetadataItem.name,
containerType: RecordTitleCellContainerType.ShowPage,
instanceId: getRecordFieldInputInstanceId({
recordId: createdRecord.id,
fieldName: labelIdentifierFieldMetadataItem.name,
prefix: RecordTitleCellContainerType.ShowPage,
}),
});
}
};
@@ -30,7 +30,7 @@ import { useLazyFetchAllRecords } from '@/object-record/hooks/useLazyFetchAllRec
import { useRestoreManyRecords } from '@/object-record/hooks/useRestoreManyRecords';
import { useUpdateOneRecord } from '@/object-record/hooks/useUpdateOneRecord';
import { useIsRecordFieldReadOnly } from '@/object-record/record-field/ui/hooks/read-only/useIsRecordFieldReadOnly';
import { isInlineCellInEditModeFamilyState } from '@/object-record/record-inline-cell/states/isInlineCellInEditModeFamilyState';
import { isTitleCellInEditModeComponentState } from '@/object-record/record-title-cell/states/isTitleCellInEditModeComponentState';
import { RecordTitleCellContainerType } from '@/object-record/record-title-cell/types/RecordTitleCellContainerType';
import { getRecordFieldInputInstanceId } from '@/object-record/utils/getRecordFieldInputId';
import { BlockEditor } from '@/ui/input/editor/components/BlockEditor';
@@ -391,7 +391,11 @@ export const ActivityRichTextEditor = ({
// Because that is how we do in the app, for example with stacked dropdowns, we always close what's open before
// letting the click being captured by a button or input that can capture it.
const isRecordTitleCellOpen = snapshot
.getLoadable(isInlineCellInEditModeFamilyState(recordTitleCellId))
.getLoadable(
isTitleCellInEditModeComponentState.atomFamily({
instanceId: recordTitleCellId,
}),
)
.getValue();
if (isRecordTitleCellOpen) {
@@ -417,7 +421,11 @@ export const ActivityRichTextEditor = ({
({ snapshot }) =>
() => {
const isRecordTitleCellOpen = snapshot
.getLoadable(isInlineCellInEditModeFamilyState(recordTitleCellId))
.getLoadable(
isTitleCellInEditModeComponentState.atomFamily({
instanceId: recordTitleCellId,
}),
)
.getValue();
if (isRecordTitleCellOpen) {
@@ -0,0 +1,44 @@
import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue';
import { RecordBoardContext } from '@/object-record/record-board/contexts/RecordBoardContext';
import { RecordBoardCardInputContextProvider } from '@/object-record/record-board/record-board-card/anchored-portal/components/RecordBoardCardInputContextProvider';
import { RECORD_BOARD_CARD_INPUT_ID_PREFIX } from '@/object-record/record-board/record-board-card/constants/RecordBoardCardInputIdPrefix';
import { RecordBoardCardContext } from '@/object-record/record-board/record-board-card/contexts/RecordBoardCardContext';
import { useRecordBoardCardMetadataFromPosition } from '@/object-record/record-board/record-board-card/hooks/useRecordBoardCardMetadataFromPosition';
import { recordBoardCardEditModePositionComponentState } from '@/object-record/record-board/record-board-card/states/recordBoardCardEditModePositionComponentState';
import { FieldInput } from '@/object-record/record-field/ui/components/FieldInput';
import { RecordInlineCellAnchoredPortal } from '@/object-record/record-inline-cell/components/RecordInlineCellAnchoredPortal';
import { RecordInlineCellEditMode } from '@/object-record/record-inline-cell/components/RecordInlineCellEditMode';
import { useContext } from 'react';
import { isDefined } from 'twenty-shared/utils';
export const RecordBoardCardCellEditModePortal = () => {
const { objectMetadataItem } = useContext(RecordBoardContext);
const { recordId } = useContext(RecordBoardCardContext);
const editModePosition = useRecoilComponentValue(
recordBoardCardEditModePositionComponentState,
);
const { editedFieldMetadataItem } = useRecordBoardCardMetadataFromPosition();
if (!isDefined(editModePosition) || !isDefined(editedFieldMetadataItem)) {
return null;
}
return (
<RecordInlineCellAnchoredPortal
position={editModePosition}
fieldMetadataItem={editedFieldMetadataItem}
objectMetadataItem={objectMetadataItem}
recordId={recordId}
instanceIdPrefix={RECORD_BOARD_CARD_INPUT_ID_PREFIX}
>
<RecordBoardCardInputContextProvider>
<RecordInlineCellEditMode>
<FieldInput />
</RecordInlineCellEditMode>
</RecordBoardCardInputContextProvider>
</RecordInlineCellAnchoredPortal>
);
};
@@ -0,0 +1,41 @@
import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue';
import { RecordBoardContext } from '@/object-record/record-board/contexts/RecordBoardContext';
import { RecordBoardCardCellHoveredPortalContent } from '@/object-record/record-board/record-board-card/anchored-portal/components/RecordBoardCardCellHoveredPortalContent';
import { RecordBoardCardInputContextProvider } from '@/object-record/record-board/record-board-card/anchored-portal/components/RecordBoardCardInputContextProvider';
import { RECORD_BOARD_CARD_INPUT_ID_PREFIX } from '@/object-record/record-board/record-board-card/constants/RecordBoardCardInputIdPrefix';
import { RecordBoardCardContext } from '@/object-record/record-board/record-board-card/contexts/RecordBoardCardContext';
import { useRecordBoardCardMetadataFromPosition } from '@/object-record/record-board/record-board-card/hooks/useRecordBoardCardMetadataFromPosition';
import { recordBoardCardHoverPositionComponentState } from '@/object-record/record-board/record-board-card/states/recordBoardCardHoverPositionComponentState';
import { RecordInlineCellAnchoredPortal } from '@/object-record/record-inline-cell/components/RecordInlineCellAnchoredPortal';
import { useContext } from 'react';
import { isDefined } from 'twenty-shared/utils';
export const RecordBoardCardCellHoveredPortal = () => {
const { objectMetadataItem } = useContext(RecordBoardContext);
const { recordId } = useContext(RecordBoardCardContext);
const hoverPosition = useRecoilComponentValue(
recordBoardCardHoverPositionComponentState,
);
const { hoveredFieldMetadataItem } = useRecordBoardCardMetadataFromPosition();
if (!isDefined(hoverPosition) || !isDefined(hoveredFieldMetadataItem)) {
return null;
}
return (
<RecordInlineCellAnchoredPortal
position={hoverPosition}
fieldMetadataItem={hoveredFieldMetadataItem}
objectMetadataItem={objectMetadataItem}
recordId={recordId}
instanceIdPrefix={RECORD_BOARD_CARD_INPUT_ID_PREFIX}
>
<RecordBoardCardInputContextProvider>
<RecordBoardCardCellHoveredPortalContent />
</RecordBoardCardInputContextProvider>
</RecordInlineCellAnchoredPortal>
);
};
@@ -0,0 +1,70 @@
import { RECORD_BOARD_CARD_INPUT_ID_PREFIX } from '@/object-record/record-board/record-board-card/constants/RecordBoardCardInputIdPrefix';
import { recordBoardCardEditModePositionComponentState } from '@/object-record/record-board/record-board-card/states/recordBoardCardEditModePositionComponentState';
import { recordBoardCardHoverPositionComponentState } from '@/object-record/record-board/record-board-card/states/recordBoardCardHoverPositionComponentState';
import { FieldDisplay } from '@/object-record/record-field/ui/components/FieldDisplay';
import { FieldInput } from '@/object-record/record-field/ui/components/FieldInput';
import { FieldContext } from '@/object-record/record-field/ui/contexts/FieldContext';
import { useOpenFieldInputEditMode } from '@/object-record/record-field/ui/hooks/useOpenFieldInputEditMode';
import { useRecordInlineCellContext } from '@/object-record/record-inline-cell/components/RecordInlineCellContext';
import { RecordInlineCellDisplayMode } from '@/object-record/record-inline-cell/components/RecordInlineCellDisplayMode';
import { RecordInlineCellHoveredPortalContent } from '@/object-record/record-inline-cell/components/RecordInlineCellHoveredPortalContent';
import { useInlineCell } from '@/object-record/record-inline-cell/hooks/useInlineCell';
import { getRecordFieldInputInstanceId } from '@/object-record/utils/getRecordFieldInputId';
import { useRecoilComponentState } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentState';
import { useSetRecoilComponentState } from '@/ui/utilities/state/component-state/hooks/useSetRecoilComponentState';
import { useContext } from 'react';
export const RecordBoardCardCellHoveredPortalContent = () => {
const { editModeContentOnly, isCentered } = useRecordInlineCellContext();
const { isRecordFieldReadOnly, recordId, fieldDefinition } =
useContext(FieldContext);
const { openInlineCell } = useInlineCell(
getRecordFieldInputInstanceId({
recordId,
fieldName: fieldDefinition.metadata.fieldName,
prefix: RECORD_BOARD_CARD_INPUT_ID_PREFIX,
}),
);
const shouldContainerBeClickable =
!isRecordFieldReadOnly && !editModeContentOnly;
const [recordBoardCardHoverPosition, setRecordBoardCardHoverPosition] =
useRecoilComponentState(recordBoardCardHoverPositionComponentState);
const setRecordBoardCardEditModePosition = useSetRecoilComponentState(
recordBoardCardEditModePositionComponentState,
);
const { openFieldInput } = useOpenFieldInputEditMode();
const handleClick = () => {
if (shouldContainerBeClickable) {
openInlineCell();
setRecordBoardCardEditModePosition(recordBoardCardHoverPosition);
openFieldInput({
fieldDefinition,
recordId,
prefix: RECORD_BOARD_CARD_INPUT_ID_PREFIX,
});
}
};
const handleMouseLeave = () => {
setRecordBoardCardHoverPosition(null);
};
return (
<RecordInlineCellHoveredPortalContent
readonly={isRecordFieldReadOnly}
isCentered={isCentered}
onMouseLeave={handleMouseLeave}
>
<RecordInlineCellDisplayMode isHovered={true} onClick={handleClick}>
{editModeContentOnly ? <FieldInput /> : <FieldDisplay />}
</RecordInlineCellDisplayMode>
</RecordInlineCellHoveredPortalContent>
);
};
@@ -0,0 +1,126 @@
import { usePersistFieldFromFieldInputContext } from '@/object-record/record-field/ui/hooks/usePersistFieldFromFieldInputContext';
import { RecordFieldComponentInstanceContext } from '@/object-record/record-field/ui/states/contexts/RecordFieldComponentInstanceContext';
import { recordBoardCardEditModePositionComponentState } from '@/object-record/record-board/record-board-card/states/recordBoardCardEditModePositionComponentState';
import {
FieldInputEventContext,
type FieldInputClickOutsideEvent,
type FieldInputEvent,
} from '@/object-record/record-field/ui/contexts/FieldInputEventContext';
import { useInlineCell } from '@/object-record/record-inline-cell/hooks/useInlineCell';
import { currentFocusIdSelector } from '@/ui/utilities/focus/states/currentFocusIdSelector';
import { useAvailableComponentInstanceId } from '@/ui/utilities/state/component-state/hooks/useAvailableComponentInstanceId';
import { useSetRecoilComponentState } from '@/ui/utilities/state/component-state/hooks/useSetRecoilComponentState';
import { useCallback } from 'react';
import { useRecoilCallback } from 'recoil';
type RecordBoardCardInputContextProviderProps = {
children: React.ReactNode;
};
export const RecordBoardCardInputContextProvider = ({
children,
}: RecordBoardCardInputContextProviderProps) => {
const { closeInlineCell } = useInlineCell();
const setRecordBoardCardEditModePosition = useSetRecoilComponentState(
recordBoardCardEditModePositionComponentState,
);
const closeInlineCellAndResetEditModePosition = useCallback(() => {
setRecordBoardCardEditModePosition(null);
closeInlineCell();
}, [closeInlineCell, setRecordBoardCardEditModePosition]);
const instanceId = useAvailableComponentInstanceId(
RecordFieldComponentInstanceContext,
);
const { persistFieldFromFieldInputContext } =
usePersistFieldFromFieldInputContext();
const handleEnter: FieldInputEvent = ({ newValue, skipPersist }) => {
if (skipPersist !== true) {
persistFieldFromFieldInputContext(newValue);
}
closeInlineCellAndResetEditModePosition();
};
const handleSubmit: FieldInputEvent = ({ newValue, skipPersist }) => {
if (skipPersist !== true) {
persistFieldFromFieldInputContext(newValue);
}
closeInlineCellAndResetEditModePosition();
};
const handleCancel = () => {
closeInlineCellAndResetEditModePosition();
};
const handleClickOutside: FieldInputClickOutsideEvent = useRecoilCallback(
({ snapshot }) =>
({ newValue, event, skipPersist }) => {
const currentFocusId = snapshot
.getLoadable(currentFocusIdSelector)
.getValue();
if (currentFocusId !== instanceId) {
return;
}
event?.preventDefault();
event?.stopImmediatePropagation();
if (skipPersist !== true) {
persistFieldFromFieldInputContext(newValue);
}
closeInlineCellAndResetEditModePosition();
},
[
closeInlineCellAndResetEditModePosition,
instanceId,
persistFieldFromFieldInputContext,
],
);
const handleEscape: FieldInputEvent = ({ newValue, skipPersist }) => {
if (skipPersist !== true) {
persistFieldFromFieldInputContext(newValue);
}
closeInlineCellAndResetEditModePosition();
};
const handleTab: FieldInputEvent = ({ newValue, skipPersist }) => {
if (skipPersist !== true) {
persistFieldFromFieldInputContext(newValue);
}
closeInlineCellAndResetEditModePosition();
};
const handleShiftTab: FieldInputEvent = ({ newValue, skipPersist }) => {
if (skipPersist !== true) {
persistFieldFromFieldInputContext(newValue);
}
closeInlineCellAndResetEditModePosition();
};
return (
<FieldInputEventContext.Provider
value={{
onCancel: handleCancel,
onEnter: handleEnter,
onEscape: handleEscape,
onClickOutside: handleClickOutside,
onShiftTab: handleShiftTab,
onSubmit: handleSubmit,
onTab: handleTab,
}}
>
{children}
</FieldInputEventContext.Provider>
);
};
@@ -11,9 +11,12 @@ import { recordBoardVisibleFieldDefinitionsComponentSelector } from '@/object-re
import { useActiveRecordBoardCard } from '@/object-record/record-board/hooks/useActiveRecordBoardCard';
import { useFocusedRecordBoardCard } from '@/object-record/record-board/hooks/useFocusedRecordBoardCard';
import { RecordBoardCardCellEditModePortal } from '@/object-record/record-board/record-board-card/anchored-portal/components/RecordBoardCardCellEditModePortal';
import { RecordBoardCardCellHoveredPortal } from '@/object-record/record-board/record-board-card/anchored-portal/components/RecordBoardCardCellHoveredPortal';
import { RecordBoardCardBody } from '@/object-record/record-board/record-board-card/components/RecordBoardCardBody';
import { RecordBoardCardHeader } from '@/object-record/record-board/record-board-card/components/RecordBoardCardHeader';
import { RECORD_BOARD_CARD_CLICK_OUTSIDE_ID } from '@/object-record/record-board/record-board-card/constants/RecordBoardCardClickOutsideId';
import { RecordBoardCardComponentInstanceContext } from '@/object-record/record-board/record-board-card/states/contexts/RecordBoardCardComponentInstanceContext';
import { RecordBoardComponentInstanceContext } from '@/object-record/record-board/states/contexts/RecordBoardComponentInstanceContext';
import { useOpenRecordFromIndexView } from '@/object-record/record-index/hooks/useOpenRecordFromIndexView';
import { useOpenDropdown } from '@/ui/layout/dropdown/hooks/useOpenDropdown';
@@ -226,44 +229,58 @@ export const RecordBoardCard = () => {
);
return (
<StyledBoardCardWrapper
data-click-outside-id={RECORD_BOARD_CARD_CLICK_OUTSIDE_ID}
onContextMenu={handleContextMenuOpen}
<RecordBoardCardComponentInstanceContext.Provider
value={{
instanceId: `record-board-card-${recordId}`,
}}
>
<InView>
<StyledCardContainer isPrimaryMultiDrag={isPrimaryMultiDrag}>
{isPrimaryMultiDrag &&
Array.from({
length: Math.min(5, multiDragState.originalSelection.length - 1),
}).map((_, index) => (
<StyledRecordBoardCardStackCard key={index} offset={index + 1} />
))}
<StyledBoardCardWrapper
data-click-outside-id={RECORD_BOARD_CARD_CLICK_OUTSIDE_ID}
onContextMenu={handleContextMenuOpen}
>
<InView>
<StyledCardContainer isPrimaryMultiDrag={isPrimaryMultiDrag}>
{isPrimaryMultiDrag &&
Array.from({
length: Math.min(
5,
multiDragState.originalSelection.length - 1,
),
}).map((_, index) => (
<StyledRecordBoardCardStackCard
key={index}
offset={index + 1}
/>
))}
<StyledBoardCard
ref={cardRef}
data-selected={isCurrentCardSelected}
data-focused={isCurrentCardFocused}
data-active={isCurrentCardActive}
onMouseLeave={onMouseLeaveBoard}
onClick={handleCardClick}
isPrimaryMultiDrag={isPrimaryMultiDrag}
isSecondaryDragged={isSecondaryDragged}
>
<RecordBoardCardHeader
isCardExpanded={isCardExpanded}
setIsCardExpanded={setIsCardExpanded}
/>
<AnimatedEaseInOut
isOpen={isCardExpanded || !isCompactModeActive}
initial={false}
<StyledBoardCard
ref={cardRef}
data-selected={isCurrentCardSelected}
data-focused={isCurrentCardFocused}
data-active={isCurrentCardActive}
onMouseLeave={onMouseLeaveBoard}
onClick={handleCardClick}
isPrimaryMultiDrag={isPrimaryMultiDrag}
isSecondaryDragged={isSecondaryDragged}
>
<RecordBoardCardBody
fieldDefinitions={visibleFieldDefinitionsFiltered}
<RecordBoardCardHeader
isCardExpanded={isCardExpanded}
setIsCardExpanded={setIsCardExpanded}
/>
</AnimatedEaseInOut>
</StyledBoardCard>
</StyledCardContainer>
</InView>
</StyledBoardCardWrapper>
<AnimatedEaseInOut
isOpen={isCardExpanded || !isCompactModeActive}
initial={false}
>
<RecordBoardCardBody
fieldDefinitions={visibleFieldDefinitionsFiltered}
/>
</AnimatedEaseInOut>
</StyledBoardCard>
</StyledCardContainer>
<RecordBoardCardCellHoveredPortal />
<RecordBoardCardCellEditModePortal />
</InView>
</StyledBoardCardWrapper>
</RecordBoardCardComponentInstanceContext.Provider>
);
};
@@ -3,6 +3,7 @@ import { RecordBoardCardBodyContainer } from '@/object-record/record-board/recor
import { StopPropagationContainer } from '@/object-record/record-board/record-board-card/components/StopPropagationContainer';
import { RECORD_BOARD_CARD_INPUT_ID_PREFIX } from '@/object-record/record-board/record-board-card/constants/RecordBoardCardInputIdPrefix';
import { RecordBoardCardContext } from '@/object-record/record-board/record-board-card/contexts/RecordBoardCardContext';
import { recordBoardCardHoverPositionComponentState } from '@/object-record/record-board/record-board-card/states/recordBoardCardHoverPositionComponentState';
import { type RecordBoardFieldDefinition } from '@/object-record/record-board/types/RecordBoardFieldDefinition';
import {
FieldContext,
@@ -15,6 +16,7 @@ import { type FieldMetadata } from '@/object-record/record-field/ui/types/FieldM
import { getFieldButtonIcon } from '@/object-record/record-field/ui/utils/getFieldButtonIcon';
import { RecordInlineCell } from '@/object-record/record-inline-cell/components/RecordInlineCell';
import { getRecordFieldInputInstanceId } from '@/object-record/utils/getRecordFieldInputId';
import { useSetRecoilComponentState } from '@/ui/utilities/state/component-state/hooks/useSetRecoilComponentState';
import { useContext } from 'react';
export const RecordBoardCardBody = ({
@@ -53,9 +55,17 @@ export const RecordBoardCardBody = ({
}),
);
const setRecordBoardCardHoverPosition = useSetRecoilComponentState(
recordBoardCardHoverPositionComponentState,
);
const handleMouseEnter = (index: number) => {
setRecordBoardCardHoverPosition(index);
};
return (
<RecordBoardCardBodyContainer>
{fieldDefinitionsWithReadOnly.map((fieldDefinition) => (
{fieldDefinitionsWithReadOnly.map((fieldDefinition, index) => (
<StopPropagationContainer key={fieldDefinition.fieldMetadataId}>
<FieldContext.Provider
value={{
@@ -79,6 +89,8 @@ export const RecordBoardCardBody = ({
useUpdateRecord: useUpdateOneRecordHook,
isDisplayModeFixHeight: true,
triggerEvent: 'CLICK',
anchorId: `${RECORD_BOARD_CARD_INPUT_ID_PREFIX}-${recordId}-${fieldDefinition.metadata.fieldName}`,
onMouseEnter: () => handleMouseEnter(index),
}}
>
<RecordFieldComponentInstanceContext.Provider
@@ -0,0 +1,54 @@
import { RecordBoardContext } from '@/object-record/record-board/contexts/RecordBoardContext';
import { recordBoardCardEditModePositionComponentState } from '@/object-record/record-board/record-board-card/states/recordBoardCardEditModePositionComponentState';
import { recordBoardCardHoverPositionComponentState } from '@/object-record/record-board/record-board-card/states/recordBoardCardHoverPositionComponentState';
import { recordBoardVisibleFieldDefinitionsComponentSelector } from '@/object-record/record-board/states/selectors/recordBoardVisibleFieldDefinitionsComponentSelector';
import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue';
import { useContext } from 'react';
import { isDefined } from 'twenty-shared/utils';
export const useRecordBoardCardMetadataFromPosition = () => {
const { objectMetadataItem } = useContext(RecordBoardContext);
const hoverPosition = useRecoilComponentValue(
recordBoardCardHoverPositionComponentState,
);
const editModePosition = useRecoilComponentValue(
recordBoardCardEditModePositionComponentState,
);
const visibleFieldDefinitions = useRecoilComponentValue(
recordBoardVisibleFieldDefinitionsComponentSelector,
);
const visibleFieldDefinitionsFiltered = visibleFieldDefinitions.filter(
(boardField) => !boardField.isLabelIdentifier,
);
const hoveredFieldDefinition = isDefined(hoverPosition)
? visibleFieldDefinitionsFiltered.at(hoverPosition)
: undefined;
const editedFieldDefinition = isDefined(editModePosition)
? visibleFieldDefinitionsFiltered.at(editModePosition)
: undefined;
const hoveredFieldMetadataItem = isDefined(hoveredFieldDefinition)
? objectMetadataItem.fields.find(
(fieldMetadataItem) =>
fieldMetadataItem.id === hoveredFieldDefinition.fieldMetadataId,
)
: undefined;
const editedFieldMetadataItem = isDefined(editedFieldDefinition)
? objectMetadataItem.fields.find(
(fieldMetadataItem) =>
fieldMetadataItem.id === editedFieldDefinition.fieldMetadataId,
)
: undefined;
return {
hoveredFieldMetadataItem,
editedFieldMetadataItem,
};
};
@@ -0,0 +1,4 @@
import { createComponentInstanceContext } from '@/ui/utilities/state/component-state/utils/createComponentInstanceContext';
export const RecordBoardCardComponentInstanceContext =
createComponentInstanceContext();
@@ -0,0 +1,9 @@
import { RecordBoardCardComponentInstanceContext } from '@/object-record/record-board/record-board-card/states/contexts/RecordBoardCardComponentInstanceContext';
import { createComponentState } from '@/ui/utilities/state/component-state/utils/createComponentState';
export const recordBoardCardEditModePositionComponentState =
createComponentState<number | null>({
key: 'recordBoardCardEditModePositionComponentState',
defaultValue: null,
componentInstanceContext: RecordBoardCardComponentInstanceContext,
});
@@ -0,0 +1,10 @@
import { RecordBoardCardComponentInstanceContext } from '@/object-record/record-board/record-board-card/states/contexts/RecordBoardCardComponentInstanceContext';
import { createComponentState } from '@/ui/utilities/state/component-state/utils/createComponentState';
export const recordBoardCardHoverPositionComponentState = createComponentState<
number | null
>({
key: 'recordBoardCardHoverPositionComponentState',
defaultValue: null,
componentInstanceContext: RecordBoardCardComponentInstanceContext,
});
@@ -1,12 +1,13 @@
import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue';
import { type ObjectMetadataItem } from '@/object-metadata/types/ObjectMetadataItem';
import { RecordFieldListCellEditModePortalContent } from '@/object-record/record-field-list/anchored-portal/components/RecordFieldListCellEditModePortalContent';
import { RecordFieldListInputContextProvider } from '@/object-record/record-field-list/anchored-portal/components/RecordFieldListInputContextProvider';
import { useFieldListFieldMetadataFromPosition } from '@/object-record/record-field-list/hooks/useFieldListFieldMetadataFromPosition';
import { RecordFieldListComponentInstanceContext } from '@/object-record/record-field-list/states/contexts/RecordFieldListComponentInstanceContext';
import { recordFieldListCellEditModePositionComponentState } from '@/object-record/record-field-list/states/recordFieldListCellEditModePositionComponentState';
import { FieldInput } from '@/object-record/record-field/ui/components/FieldInput';
import { RecordInlineCellAnchoredPortal } from '@/object-record/record-inline-cell/components/RecordInlineCellAnchoredPortal';
import { RecordInlineCellEditMode } from '@/object-record/record-inline-cell/components/RecordInlineCellEditMode';
import { useAvailableComponentInstanceIdOrThrow } from '@/ui/utilities/state/component-state/hooks/useAvailableComponentInstanceIdOrThrow';
import { isDefined } from 'twenty-shared/utils';
@@ -41,10 +42,12 @@ export const RecordFieldListCellEditModePortal = ({
fieldMetadataItem={editedFieldMetadataItem}
objectMetadataItem={objectMetadataItem}
recordId={recordId}
anchorIdPrefix={instanceId}
instanceIdPrefix={instanceId}
>
<RecordFieldListInputContextProvider>
<RecordFieldListCellEditModePortalContent />
<RecordInlineCellEditMode>
<FieldInput />
</RecordInlineCellEditMode>
</RecordFieldListInputContextProvider>
</RecordInlineCellAnchoredPortal>
);
@@ -1,10 +0,0 @@
import { FieldInput } from '@/object-record/record-field/ui/components/FieldInput';
import { RecordInlineCellEditMode } from '@/object-record/record-inline-cell/components/RecordInlineCellEditMode';
export const RecordFieldListCellEditModePortalContent = () => {
return (
<RecordInlineCellEditMode>
<FieldInput />
</RecordInlineCellEditMode>
);
};
@@ -41,7 +41,7 @@ export const RecordFieldListCellHoveredPortal = ({
fieldMetadataItem={hoveredFieldMetadataItem}
objectMetadataItem={objectMetadataItem}
recordId={recordId}
anchorIdPrefix={instanceId}
instanceIdPrefix={instanceId}
>
<RecordFieldListInputContextProvider>
<RecordFieldListCellHoveredPortalContent />
@@ -111,7 +111,11 @@ export const RecordFieldList = ({
useUpdateRecord: useUpdateOneObjectRecordMutation,
isDisplayModeFixHeight: true,
onMouseEnter: () => handleMouseEnter(index),
anchorId: `${instanceId}-${index}`,
anchorId: `${getRecordFieldInputInstanceId({
recordId: objectRecordId,
fieldName: fieldMetadataItem.name,
prefix: instanceId,
})}`,
isRecordFieldReadOnly: isRecordFieldReadOnly({
isRecordReadOnly,
objectPermissions:
@@ -178,9 +182,11 @@ export const RecordFieldList = ({
handleMouseEnter(
index + (inlineRelationFieldMetadataItems?.length ?? 0),
),
anchorId: `${instanceId}-${
index + (inlineRelationFieldMetadataItems?.length ?? 0)
}`,
anchorId: `${getRecordFieldInputInstanceId({
recordId: objectRecordId,
fieldName: fieldMetadataItem.name,
prefix: instanceId,
})}`,
}}
>
<RecordFieldComponentInstanceContext.Provider
@@ -15,13 +15,10 @@ import {
type FieldInputEvent,
} from '@/object-record/record-field/ui/contexts/FieldInputEventContext';
import { usePersistFieldFromFieldInputContext } from '@/object-record/record-field/ui/hooks/usePersistFieldFromFieldInputContext';
import { RecordFieldComponentInstanceContext } from '@/object-record/record-field/ui/states/contexts/RecordFieldComponentInstanceContext';
import { isInlineCellInEditModeFamilyState } from '@/object-record/record-inline-cell/states/isInlineCellInEditModeFamilyState';
import { getDropdownFocusIdForRecordField } from '@/object-record/utils/getDropdownFocusIdForRecordField';
import { useGoBackToPreviousDropdownFocusId } from '@/ui/layout/dropdown/hooks/useGoBackToPreviousDropdownFocusId';
import { activeDropdownFocusIdState } from '@/ui/layout/dropdown/states/activeDropdownFocusIdState';
import { useAvailableComponentInstanceIdOrThrow } from '@/ui/utilities/state/component-state/hooks/useAvailableComponentInstanceIdOrThrow';
import { useRecoilCallback, useSetRecoilState } from 'recoil';
import { useRecoilCallback } from 'recoil';
import { useIcons } from 'twenty-ui/display';
import { RecordInlineCellContainer } from './RecordInlineCellContainer';
import {
@@ -82,23 +79,10 @@ export const RecordInlineCell = ({
const { goBackToPreviousDropdownFocusId } =
useGoBackToPreviousDropdownFocusId();
const recordFieldComponentInstanceId = useAvailableComponentInstanceIdOrThrow(
RecordFieldComponentInstanceContext,
);
const setIsInlineCellInEditMode = useSetRecoilState(
isInlineCellInEditModeFamilyState(recordFieldComponentInstanceId),
);
const closeInlineCell = useCallback(() => {
onCloseEditMode();
setIsInlineCellInEditMode(false);
goBackToPreviousDropdownFocusId();
}, [
onCloseEditMode,
setIsInlineCellInEditMode,
goBackToPreviousDropdownFocusId,
]);
}, [onCloseEditMode, goBackToPreviousDropdownFocusId]);
const { persistFieldFromFieldInputContext } =
usePersistFieldFromFieldInputContext();
@@ -11,6 +11,7 @@ import { FieldFocusContextProvider } from '@/object-record/record-field/ui/conte
import { useIsRecordFieldReadOnly } from '@/object-record/record-field/ui/hooks/read-only/useIsRecordFieldReadOnly';
import { RecordFieldComponentInstanceContext } from '@/object-record/record-field/ui/states/contexts/RecordFieldComponentInstanceContext';
import { RecordInlineCellAnchoredPortalContext } from '@/object-record/record-inline-cell/components/RecordInlineCellAnchoredPortalContext';
import { RecordInlineCellCloseOnCommandMenuOpeningEffect } from '@/object-record/record-inline-cell/components/RecordInlineCellCloseOnCommandMenuOpeningEffect';
import { getRecordFieldInputInstanceId } from '@/object-record/utils/getRecordFieldInputId';
import { createPortal } from 'react-dom';
import { isDefined } from 'twenty-shared/utils';
@@ -23,20 +24,25 @@ type RecordInlineCellAnchoredPortalProps = {
>;
objectMetadataItem: ObjectMetadataItem;
recordId: string;
anchorIdPrefix: string;
instanceIdPrefix: string;
children: React.ReactNode;
};
export const RecordInlineCellAnchoredPortal = ({
position,
fieldMetadataItem,
objectMetadataItem,
recordId,
anchorIdPrefix,
instanceIdPrefix,
children,
}: RecordInlineCellAnchoredPortalProps) => {
const fieldInstanceId = getRecordFieldInputInstanceId({
recordId,
fieldName: fieldMetadataItem.name,
prefix: instanceIdPrefix,
});
const anchorElement = document.body.querySelector<HTMLAnchorElement>(
`#${anchorIdPrefix}-${position}`,
`#${fieldInstanceId}`,
);
const isRecordFieldReadOnly = useIsRecordFieldReadOnly({
@@ -88,16 +94,13 @@ export const RecordInlineCellAnchoredPortal = ({
{createPortal(
<RecordFieldComponentInstanceContext.Provider
value={{
instanceId: getRecordFieldInputInstanceId({
recordId,
fieldName: fieldMetadataItem.name,
prefix: anchorIdPrefix,
}),
instanceId: fieldInstanceId,
}}
>
<RecordInlineCellAnchoredPortalContext>
{children}
</RecordInlineCellAnchoredPortalContext>
<RecordInlineCellCloseOnCommandMenuOpeningEffect />
</RecordFieldComponentInstanceContext.Provider>,
anchorElement,
)}
@@ -9,8 +9,6 @@ import { getRecordFieldInputInstanceId } from '@/object-record/utils/getRecordFi
import { assertFieldMetadata } from '@/object-record/record-field/ui/types/guards/assertFieldMetadata';
import { isFieldText } from '@/object-record/record-field/ui/types/guards/isFieldText';
import { RecordInlineCellCloseOnCommandMenuOpeningEffect } from '@/object-record/record-inline-cell/components/RecordInlineCellCloseOnCommandMenuOpeningEffect';
import { useInlineCell } from '@/object-record/record-inline-cell/hooks/useInlineCell';
import {
AppTooltip,
OverflowingTextWithTooltip,
@@ -88,23 +86,12 @@ export const StyledSkeletonDiv = styled.div`
`;
export const RecordInlineCellContainer = () => {
const {
readonly,
IconLabel,
label,
labelWidth,
showLabel,
editModeContentOnly,
} = useRecordInlineCellContext();
const { isInlineCellInEditMode, openInlineCell } = useInlineCell();
const { readonly, IconLabel, label, labelWidth, showLabel } =
useRecordInlineCellContext();
const { recordId, fieldDefinition, onMouseEnter, onMouseLeave, anchorId } =
useContext(FieldContext);
const shouldContainerBeClickable =
!readonly && !editModeContentOnly && !isInlineCellInEditMode;
if (isFieldText(fieldDefinition)) {
assertFieldMetadata(FieldMetadataType.TEXT, isFieldText, fieldDefinition);
}
@@ -136,7 +123,6 @@ export const RecordInlineCellContainer = () => {
readonly={readonly ?? false}
onMouseEnter={handleContainerMouseEnter}
onMouseLeave={handleContainerMouseLeave}
onClick={shouldContainerBeClickable ? openInlineCell : undefined}
>
{(IconLabel || label) && (
<StyledLabelAndIconContainer id={labelId}>
@@ -164,9 +150,7 @@ export const RecordInlineCellContainer = () => {
)}
</StyledLabelAndIconContainer>
)}
{isInlineCellInEditMode && (
<RecordInlineCellCloseOnCommandMenuOpeningEffect />
)}
<StyledValueContainer readonly={readonly ?? false} id={anchorId}>
<RecordInlineCellValue />
</StyledValueContainer>
@@ -1,12 +1,10 @@
import { useContext } from 'react';
import { useRecoilState } from 'recoil';
import { FieldContext } from '@/object-record/record-field/ui/contexts/FieldContext';
import { useInitDraftValue } from '@/object-record/record-field/ui/hooks/useInitDraftValue';
import { RecordFieldComponentInstanceContext } from '@/object-record/record-field/ui/states/contexts/RecordFieldComponentInstanceContext';
import { useRecordInlineCellContext } from '@/object-record/record-inline-cell/components/RecordInlineCellContext';
import { isInlineCellInEditModeFamilyState } from '@/object-record/record-inline-cell/states/isInlineCellInEditModeFamilyState';
import { getDropdownFocusIdForRecordField } from '@/object-record/utils/getDropdownFocusIdForRecordField';
import { useGoBackToPreviousDropdownFocusId } from '@/ui/layout/dropdown/hooks/useGoBackToPreviousDropdownFocusId';
import { useSetActiveDropdownFocusIdAndMemorizePrevious } from '@/ui/layout/dropdown/hooks/useSetFocusedDropdownIdAndMemorizePrevious';
@@ -22,10 +20,6 @@ export const useInlineCell = (
recordFieldComponentInstanceIdFromProps,
);
const [isInlineCellInEditMode, setIsInlineCellInEditMode] = useRecoilState(
isInlineCellInEditModeFamilyState(recordFieldComponentInstanceId),
);
const { onOpenEditMode, onCloseEditMode } = useRecordInlineCellContext();
const { setActiveDropdownFocusIdAndMemorizePrevious } =
@@ -37,14 +31,12 @@ export const useInlineCell = (
const closeInlineCell = () => {
onCloseEditMode?.();
setIsInlineCellInEditMode(false);
goBackToPreviousDropdownFocusId();
};
const openInlineCell = () => {
onOpenEditMode?.();
setIsInlineCellInEditMode(true);
initFieldInputDraftValue({
recordId,
fieldDefinition,
@@ -61,7 +53,6 @@ export const useInlineCell = (
};
return {
isInlineCellInEditMode,
closeInlineCell,
openInlineCell,
};
@@ -1,9 +0,0 @@
import { createFamilyState } from '@/ui/utilities/state/utils/createFamilyState';
export const isInlineCellInEditModeFamilyState = createFamilyState<
boolean,
string
>({
key: 'isInlineCellInEditModeScopedState',
defaultValue: false,
});
@@ -8,6 +8,7 @@ import { useRecordTitleCell } from '@/object-record/record-title-cell/hooks/useR
import { RecordTitleCellContainerType } from '@/object-record/record-title-cell/types/RecordTitleCellContainerType';
import { type ObjectRecord } from '@/object-record/types/ObjectRecord';
import { canOpenObjectInSidePanel } from '@/object-record/utils/canOpenObjectInSidePanel';
import { getRecordFieldInputInstanceId } from '@/object-record/utils/getRecordFieldInputId';
import { AppPath } from '@/types/AppPath';
import { ViewOpenRecordInType } from '@/views/types/ViewOpenRecordInType';
import { useRecoilCallback } from 'recoil';
@@ -15,11 +16,13 @@ import { isDefined } from 'twenty-shared/utils';
import { v4 } from 'uuid';
import { useNavigateApp } from '~/hooks/useNavigateApp';
type UseCreateNewIndexRecordProps = {
objectMetadataItem: ObjectMetadataItem;
};
export const useCreateNewIndexRecord = ({
objectMetadataItem,
}: {
objectMetadataItem: ObjectMetadataItem;
}) => {
}: UseCreateNewIndexRecordProps) => {
const { openRecordInCommandMenu } = useOpenRecordInCommandMenu();
const { createOneRecord } = useCreateOneRecord({
@@ -67,7 +70,11 @@ export const useCreateNewIndexRecord = ({
openRecordTitleCell({
recordId,
fieldName: labelIdentifierFieldMetadataItem.name,
containerType: RecordTitleCellContainerType.ShowPage,
instanceId: getRecordFieldInputInstanceId({
recordId,
fieldName: labelIdentifierFieldMetadataItem.name,
prefix: RecordTitleCellContainerType.ShowPage,
}),
});
}
} else {
@@ -19,6 +19,7 @@ import {
import { RecordTitleCellFieldDisplay } from '@/object-record/record-title-cell/components/RecordTitleCellFieldDisplay';
import { RecordTitleCellFieldInput } from '@/object-record/record-title-cell/components/RecordTitleCellFieldInput';
import { useRecordTitleCell } from '@/object-record/record-title-cell/hooks/useRecordTitleCell';
import { RecordTitleCellComponentInstanceContext } from '@/object-record/record-title-cell/states/contexts/RecordTitleCellComponentInstanceContext';
import { type RecordTitleCellContainerType } from '@/object-record/record-title-cell/types/RecordTitleCellContainerType';
import { getRecordFieldInputInstanceId } from '@/object-record/utils/getRecordFieldInputId';
import { useRecoilCallback } from 'recoil';
@@ -42,12 +43,8 @@ export const RecordTitleCell = ({
const { closeRecordTitleCell } = useRecordTitleCell();
const closeCell = useCallback(() => {
closeRecordTitleCell({
recordId,
fieldName: fieldDefinition.metadata.fieldName,
containerType,
});
}, [closeRecordTitleCell, containerType, fieldDefinition, recordId]);
closeRecordTitleCell();
}, [closeRecordTitleCell]);
const { persistFieldFromFieldInputContext } =
usePersistFieldFromFieldInputContext();
@@ -132,11 +129,21 @@ export const RecordTitleCell = ({
}),
}}
>
<FieldFocusContextProvider>
<RecordTitleCellContext.Provider value={recordTitleCellContextValue}>
<RecordTitleCellContainer />
</RecordTitleCellContext.Provider>
</FieldFocusContextProvider>
<RecordTitleCellComponentInstanceContext.Provider
value={{
instanceId: getRecordFieldInputInstanceId({
recordId,
fieldName: fieldDefinition.metadata.fieldName,
prefix: containerType,
}),
}}
>
<FieldFocusContextProvider>
<RecordTitleCellContext.Provider value={recordTitleCellContextValue}>
<RecordTitleCellContainer />
</RecordTitleCellContext.Provider>
</FieldFocusContextProvider>
</RecordTitleCellComponentInstanceContext.Provider>
</RecordFieldComponentInstanceContext.Provider>
);
};
@@ -1,5 +1,6 @@
import { useInlineCell } from '@/object-record/record-inline-cell/hooks/useInlineCell';
import { RecordTitleCellContext } from '@/object-record/record-title-cell/components/RecordTitleCellContext';
import { isTitleCellInEditModeComponentState } from '@/object-record/record-title-cell/states/isTitleCellInEditModeComponentState';
import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue';
import { useContext } from 'react';
import { isDefined } from 'twenty-shared/utils';
@@ -8,11 +9,13 @@ export const RecordTitleCellContainer = () => {
RecordTitleCellContext,
);
const { isInlineCellInEditMode } = useInlineCell();
const isTitleCellInEditMode = useRecoilComponentValue(
isTitleCellInEditModeComponentState,
);
if (isDefined(isReadOnly) && isReadOnly) {
return <>{displayModeContent}</>;
}
return <>{isInlineCellInEditMode ? editModeContent : displayModeContent}</>;
return <>{isTitleCellInEditMode ? editModeContent : displayModeContent}</>;
};
@@ -2,6 +2,7 @@ import { FieldContext } from '@/object-record/record-field/ui/contexts/FieldCont
import { recordStoreFamilyState } from '@/object-record/record-store/states/recordStoreFamilyState';
import { useRecordTitleCell } from '@/object-record/record-title-cell/hooks/useRecordTitleCell';
import { type RecordTitleCellContainerType } from '@/object-record/record-title-cell/types/RecordTitleCellContainerType';
import { getRecordFieldInputInstanceId } from '@/object-record/utils/getRecordFieldInputId';
import { withTheme, type Theme } from '@emotion/react';
import styled from '@emotion/styled';
import { useContext } from 'react';
@@ -50,7 +51,11 @@ export const RecordTitleCellSingleTextDisplayMode = ({
openRecordTitleCell({
recordId,
fieldName: fieldDefinition.metadata.fieldName,
containerType,
instanceId: getRecordFieldInputInstanceId({
recordId,
fieldName: fieldDefinition.metadata.fieldName,
prefix: containerType,
}),
});
}}
>
@@ -1,20 +1,30 @@
import { useContextStoreObjectMetadataItem } from '@/context-store/hooks/useContextStoreObjectMetadataItem';
import { formatFieldMetadataItemAsColumnDefinition } from '@/object-metadata/utils/formatFieldMetadataItemAsColumnDefinition';
import { useInitDraftValue } from '@/object-record/record-field/ui/hooks/useInitDraftValue';
import { isInlineCellInEditModeFamilyState } from '@/object-record/record-inline-cell/states/isInlineCellInEditModeFamilyState';
import { type RecordTitleCellContainerType } from '@/object-record/record-title-cell/types/RecordTitleCellContainerType';
import { getRecordFieldInputInstanceId } from '@/object-record/utils/getRecordFieldInputId';
import { RecordTitleCellComponentInstanceContext } from '@/object-record/record-title-cell/states/contexts/RecordTitleCellComponentInstanceContext';
import { isTitleCellInEditModeComponentState } from '@/object-record/record-title-cell/states/isTitleCellInEditModeComponentState';
import { useGoBackToPreviousDropdownFocusId } from '@/ui/layout/dropdown/hooks/useGoBackToPreviousDropdownFocusId';
import { usePushFocusItemToFocusStack } from '@/ui/utilities/focus/hooks/usePushFocusItemToFocusStack';
import { useRemoveFocusItemFromFocusStackById } from '@/ui/utilities/focus/hooks/useRemoveFocusItemFromFocusStackById';
import { FocusComponentType } from '@/ui/utilities/focus/types/FocusComponentType';
import { useAvailableComponentInstanceId } from '@/ui/utilities/state/component-state/hooks/useAvailableComponentInstanceId';
import { useRecoilCallback } from 'recoil';
import { isDefined } from 'twenty-shared/utils';
type OpenTitleCellFunctionParams = {
recordId: string;
fieldName: string;
instanceId?: string;
};
export const useRecordTitleCell = () => {
const { goBackToPreviousDropdownFocusId } =
useGoBackToPreviousDropdownFocusId();
const instanceId = useAvailableComponentInstanceId(
RecordTitleCellComponentInstanceContext,
);
const { pushFocusItemToFocusStack } = usePushFocusItemToFocusStack();
const { removeFocusItemFromFocusStackById } =
useRemoveFocusItemFromFocusStackById();
@@ -23,37 +33,32 @@ export const useRecordTitleCell = () => {
const closeRecordTitleCell = useRecoilCallback(
({ set }) =>
({
recordId,
fieldName,
containerType,
}: {
recordId: string;
fieldName: string;
containerType: RecordTitleCellContainerType;
}) => {
(instanceIdFromProps?: string) => {
const computedInstanceId = instanceIdFromProps ?? instanceId;
if (!isDefined(computedInstanceId)) {
throw new Error(
'Instance ID is not defined in closeRecordTitleCell this should not happen.',
);
}
set(
isInlineCellInEditModeFamilyState(
getRecordFieldInputInstanceId({
recordId,
fieldName,
prefix: containerType,
}),
),
isTitleCellInEditModeComponentState.atomFamily({
instanceId: computedInstanceId,
}),
false,
);
removeFocusItemFromFocusStackById({
focusId: getRecordFieldInputInstanceId({
recordId,
fieldName,
prefix: containerType,
}),
focusId: computedInstanceId,
});
goBackToPreviousDropdownFocusId();
},
[goBackToPreviousDropdownFocusId, removeFocusItemFromFocusStackById],
[
goBackToPreviousDropdownFocusId,
instanceId,
removeFocusItemFromFocusStackById,
],
);
const initFieldInputDraftValue = useInitDraftValue();
@@ -63,31 +68,27 @@ export const useRecordTitleCell = () => {
({
recordId,
fieldName,
containerType,
}: {
recordId: string;
fieldName: string;
containerType: RecordTitleCellContainerType;
}) => {
instanceId: instanceIdFromProps,
}: OpenTitleCellFunctionParams) => {
if (!isDefined(objectMetadataItem)) {
throw new Error(
'Cannot find object metadata item in openRecordTitleCell this should not happen.',
);
}
const computedInstanceId = instanceIdFromProps ?? instanceId;
if (!isDefined(computedInstanceId)) {
throw new Error(
'Instance ID is not defined in openRecordTitleCell this should not happen.',
);
}
pushFocusItemToFocusStack({
focusId: getRecordFieldInputInstanceId({
recordId,
fieldName,
prefix: containerType,
}),
focusId: computedInstanceId,
component: {
type: FocusComponentType.OPENED_FIELD_INPUT,
instanceId: getRecordFieldInputInstanceId({
recordId,
fieldName,
prefix: containerType,
}),
instanceId: computedInstanceId,
},
globalHotkeysConfig: {
enableGlobalHotkeysConflictingWithKeyboard: false,
@@ -95,12 +96,12 @@ export const useRecordTitleCell = () => {
},
});
const recordTitleCellId = getRecordFieldInputInstanceId({
recordId,
fieldName,
prefix: containerType,
});
set(isInlineCellInEditModeFamilyState(recordTitleCellId), true);
set(
isTitleCellInEditModeComponentState.atomFamily({
instanceId: computedInstanceId,
}),
true,
);
const fieldDefinitions = objectMetadataItem.fields.map(
(fieldMetadataItem, index) =>
@@ -124,10 +125,15 @@ export const useRecordTitleCell = () => {
initFieldInputDraftValue({
recordId,
fieldDefinition,
fieldComponentInstanceId: recordTitleCellId,
fieldComponentInstanceId: computedInstanceId,
});
},
[initFieldInputDraftValue, pushFocusItemToFocusStack, objectMetadataItem],
[
objectMetadataItem,
instanceId,
pushFocusItemToFocusStack,
initFieldInputDraftValue,
],
);
return {
@@ -0,0 +1,4 @@
import { createComponentInstanceContext } from '@/ui/utilities/state/component-state/utils/createComponentInstanceContext';
export const RecordTitleCellComponentInstanceContext =
createComponentInstanceContext();
@@ -0,0 +1,9 @@
import { RecordTitleCellComponentInstanceContext } from '@/object-record/record-title-cell/states/contexts/RecordTitleCellComponentInstanceContext';
import { createComponentState } from '@/ui/utilities/state/component-state/utils/createComponentState';
export const isTitleCellInEditModeComponentState =
createComponentState<boolean>({
key: 'isTitleCellInEditModeComponentState',
defaultValue: false,
componentInstanceContext: RecordTitleCellComponentInstanceContext,
});