Add a CARD layout to the Field widget (#16995)

Closes https://github.com/twentyhq/core-team-issues/issues/1943

## Demo



https://github.com/user-attachments/assets/ea86e1e6-6495-42b8-8dd3-e2bf7d295bab

---------

Co-authored-by: cubic-dev-ai[bot] <191113872+cubic-dev-ai[bot]@users.noreply.github.com>
This commit is contained in:
Baptiste Devessier
2026-01-08 16:43:34 +01:00
committed by GitHub
parent 28e79de7b0
commit f1aee7fd18
21 changed files with 949 additions and 51 deletions
@@ -12,10 +12,7 @@ import { useDeleteOneRecord } from '@/object-record/hooks/useDeleteOneRecord';
import { useObjectPermissionsForObject } from '@/object-record/hooks/useObjectPermissionsForObject';
import { useUpdateOneRecord } from '@/object-record/hooks/useUpdateOneRecord';
import { RecordFieldList } from '@/object-record/record-field-list/components/RecordFieldList';
import {
RecordFieldsScopeContextProvider,
useRecordFieldsScopeContextOrThrow,
} from '@/object-record/record-field-list/contexts/RecordFieldsScopeContext';
import { useRecordFieldsScopeContextOrThrow } from '@/object-record/record-field-list/contexts/RecordFieldsScopeContext';
import { RecordDetailRecordsListItemContainer } from '@/object-record/record-field-list/record-detail-section/components/RecordDetailRecordsListItemContainer';
import { FieldContext } from '@/object-record/record-field/ui/contexts/FieldContext';
import { FieldInputEventContext } from '@/object-record/record-field/ui/contexts/FieldInputEventContext';
@@ -31,7 +28,6 @@ import { useCloseDropdown } from '@/ui/layout/dropdown/hooks/useCloseDropdown';
import { isDropdownOpenComponentState } from '@/ui/layout/dropdown/states/isDropdownOpenComponentState';
import { ConfirmationModal } from '@/ui/layout/modal/components/ConfirmationModal';
import { useModal } from '@/ui/layout/modal/hooks/useModal';
import { useIsInRightDrawerOrThrow } from '@/ui/layout/right-drawer/contexts/RightDrawerContext';
import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue';
import { useSetRecoilComponentState } from '@/ui/utilities/state/component-state/hooks/useSetRecoilComponentState';
import { t } from '@lingui/core/macro';
@@ -113,7 +109,6 @@ export const RecordDetailRelationRecordsListItem = ({
const { onSubmit } = useContext(FieldInputEventContext);
const { openModal } = useModal();
const { isInRightDrawer } = useIsInRightDrawerOrThrow();
const { relationType, objectMetadataNameSingular } =
fieldDefinition.metadata as FieldRelationMetadata;
@@ -156,7 +151,7 @@ export const RecordDetailRelationRecordsListItem = ({
relationObjectMetadataNameSingular ===
CoreObjectNameSingular.WorkspaceMember;
const dropdownInstanceId = `record-field-card-menu-${relationFieldMetadataId}-${relationRecord.id}`;
const dropdownInstanceId = `record-field-card-menu:${scopeInstanceId}:${relationFieldMetadataId}:${relationRecord.id}`;
const { closeDropdown } = useCloseDropdown();
const isDropdownOpen = useRecoilComponentValue(
@@ -199,6 +194,7 @@ export const RecordDetailRelationRecordsListItem = ({
relationFieldMetadataItem?.name ?? '',
)]: null,
};
const handleDetach = () => {
closeDropdown(dropdownInstanceId);
@@ -243,12 +239,15 @@ export const RecordDetailRelationRecordsListItem = ({
return (
<>
<StyledListItem isDropdownOpen={isDropdownOpen}>
<StyledListItem
isDropdownOpen={isDropdownOpen}
data-testid="record-detail-records-list-item"
>
<RecordChip
record={relationRecord}
objectNameSingular={relationObjectMetadataItem.nameSingular}
/>
<StyledClickableZone onClick={handleClick}>
<StyledClickableZone onClick={handleClick} data-testid="expand-button">
<LightIconButton
className="displayOnHover"
Icon={AnimatedIconChevronDown}
@@ -290,21 +289,15 @@ export const RecordDetailRelationRecordsListItem = ({
)}
</StyledListItem>
<AnimatedEaseInOut isOpen={isExpanded}>
<RecordFieldsScopeContextProvider
value={{
scopeInstanceId: `record-detail-relation-${relationRecord.id}${isInRightDrawer ? '-right-drawer' : ''}`,
}}
>
<RecordFieldList
instanceId={`record-detail-relation-${relationRecord.id}-${isInRightDrawer ? 'right-drawer' : ''}`}
objectNameSingular={relationObjectMetadataNameSingular}
objectRecordId={relationRecord.id}
showDuplicatesSection={false}
showRelationSections={false}
excludeCreatedAtAndUpdatedAt={true}
excludeFieldMetadataIds={[relationFieldMetadataId]}
/>
</RecordFieldsScopeContextProvider>
<RecordFieldList
instanceId={`${scopeInstanceId}-relation-${relationRecord.id}`}
objectNameSingular={relationObjectMetadataNameSingular}
objectRecordId={relationRecord.id}
showDuplicatesSection={false}
showRelationSections={false}
excludeCreatedAtAndUpdatedAt={true}
excludeFieldMetadataIds={[relationFieldMetadataId]}
/>
</AnimatedEaseInOut>
{createPortal(
<ConfirmationModal