diff --git a/packages/twenty-front/src/modules/object-record/object-options-dropdown/components/__stories__/ObjectOptionsDropdownContent.stories.tsx b/packages/twenty-front/src/modules/object-record/object-options-dropdown/components/__stories__/ObjectOptionsDropdownContent.stories.tsx index 200b735b0f8..527988e4c0e 100644 --- a/packages/twenty-front/src/modules/object-record/object-options-dropdown/components/__stories__/ObjectOptionsDropdownContent.stories.tsx +++ b/packages/twenty-front/src/modules/object-record/object-options-dropdown/components/__stories__/ObjectOptionsDropdownContent.stories.tsx @@ -10,6 +10,7 @@ import { RecordIndexContextProvider } from '@/object-record/record-index/context import { useRecordIndexFieldMetadataDerivedStates } from '@/object-record/record-index/hooks/useRecordIndexFieldMetadataDerivedStates'; import { RecordTableComponentInstanceContext } from '@/object-record/record-table/states/context/RecordTableComponentInstanceContext'; import { DropdownContent } from '@/ui/layout/dropdown/components/DropdownContent'; +import { DropdownComponentInstanceContext } from '@/ui/layout/dropdown/contexts/DropdownComponentInstanceContext'; import { ViewComponentInstanceContext } from '@/views/states/contexts/ViewComponentInstanceContext'; import { ViewType } from '@/views/types/ViewType'; import { useEffect } from 'react'; @@ -105,21 +106,25 @@ const createStory = (contentId: ObjectOptionsContentId | null): Story => ({ recordFieldByFieldMetadataItemId, }} > - {}, - resetContent: () => {}, - dropdownId: OBJECT_OPTIONS_DROPDOWN_ID, - }} + - - - - + {}, + resetContent: () => {}, + dropdownId: OBJECT_OPTIONS_DROPDOWN_ID, + }} + > + + + + + ); }, diff --git a/packages/twenty-front/src/modules/ui/layout/draggable-list/components/DraggableItem.tsx b/packages/twenty-front/src/modules/ui/layout/draggable-list/components/DraggableItem.tsx index 00234c9551a..8b79e3f8462 100644 --- a/packages/twenty-front/src/modules/ui/layout/draggable-list/components/DraggableItem.tsx +++ b/packages/twenty-front/src/modules/ui/layout/draggable-list/components/DraggableItem.tsx @@ -1,6 +1,7 @@ import { useTheme } from '@emotion/react'; import { Draggable } from '@hello-pangea/dnd'; import { isFunction } from '@sniptt/guards'; +import { isDefined } from 'twenty-shared/utils'; type DraggableItemProps = { draggableId: string; @@ -12,6 +13,7 @@ type DraggableItemProps = { isInsideScrollableContainer?: boolean; draggableComponentStyles?: React.CSSProperties; disableDraggingBackground?: boolean; + containerOffsetY?: number; }; export const DraggableItem = ({ @@ -22,6 +24,7 @@ export const DraggableItem = ({ isInsideScrollableContainer, draggableComponentStyles, disableDraggingBackground, + containerOffsetY, }: DraggableItemProps) => { const theme = useTheme(); @@ -47,11 +50,15 @@ export const DraggableItem = ({ ...draggableComponentStyles, ...draggableStyle, left: 'auto', - ...(isInsideScrollableContainer ? {} : { top: 'auto' }), transform: draggableStyle?.transform?.replace( /\(-?\d+px,/, '(0,', ), + ...(isInsideScrollableContainer + ? { + top: `${(isDefined(draggableStyle) && 'top' in draggableStyle ? draggableStyle.top : 0) - (containerOffsetY ?? 0)}px`, + } + : { top: 'auto' }), background: !disableDraggingBackground && isDragging ? theme.background.transparent.light diff --git a/packages/twenty-front/src/modules/ui/layout/dropdown/components/Dropdown.tsx b/packages/twenty-front/src/modules/ui/layout/dropdown/components/Dropdown.tsx index 057707a3d2a..a64aed1ab79 100644 --- a/packages/twenty-front/src/modules/ui/layout/dropdown/components/Dropdown.tsx +++ b/packages/twenty-front/src/modules/ui/layout/dropdown/components/Dropdown.tsx @@ -9,6 +9,7 @@ import { DropdownComponentInstanceContext } from '@/ui/layout/dropdown/contexts/ import { useToggleDropdown } from '@/ui/layout/dropdown/hooks/useToggleDropdown'; import { dropdownMaxHeightComponentState } from '@/ui/layout/dropdown/states/internal/dropdownMaxHeightComponentState'; import { dropdownMaxWidthComponentState } from '@/ui/layout/dropdown/states/internal/dropdownMaxWidthComponentState'; +import { dropdownYPositionComponentState } from '@/ui/layout/dropdown/states/internal/dropdownYPositionComponentState'; import { isDropdownOpenComponentState } from '@/ui/layout/dropdown/states/isDropdownOpenComponentState'; import { type DropdownOffset } from '@/ui/layout/dropdown/types/DropdownOffset'; import { type GlobalHotkeysConfig } from '@/ui/utilities/hotkey/types/GlobalHotkeysConfig'; @@ -117,6 +118,11 @@ export const Dropdown = ({ dropdownId, ); + const setDropdownYPosition = useSetRecoilComponentState( + dropdownYPositionComponentState, + dropdownId, + ); + const isMobile = useIsMobile(); const bottomAutoresizePadding = isMobile ? (middlewareBoundaryPadding.bottomMobile ?? @@ -143,7 +149,7 @@ export const Dropdown = ({ ...boundaryOptions, }), size({ - apply: ({ availableHeight, availableWidth }) => { + apply: ({ availableHeight, availableWidth, y: floatingY }) => { flushSync(() => { const maxHeightToApply = availableHeight < DROPDOWN_RESIZE_MIN_HEIGHT @@ -157,6 +163,7 @@ export const Dropdown = ({ setDropdownMaxHeight(maxHeightToApply); setDropdownMaxWidth(maxWidthToApply); + setDropdownYPosition(floatingY); }); }, ...boundaryOptions, diff --git a/packages/twenty-front/src/modules/ui/layout/dropdown/states/internal/dropdownYPositionComponentState.ts b/packages/twenty-front/src/modules/ui/layout/dropdown/states/internal/dropdownYPositionComponentState.ts new file mode 100644 index 00000000000..ef3a5626e1c --- /dev/null +++ b/packages/twenty-front/src/modules/ui/layout/dropdown/states/internal/dropdownYPositionComponentState.ts @@ -0,0 +1,10 @@ +import { DropdownComponentInstanceContext } from '@/ui/layout/dropdown/contexts/DropdownComponentInstanceContext'; +import { createComponentState } from '@/ui/utilities/state/component-state/utils/createComponentState'; + +export const dropdownYPositionComponentState = createComponentState< + number | undefined +>({ + key: 'dropdownYPositionComponentState', + componentInstanceContext: DropdownComponentInstanceContext, + defaultValue: undefined, +}); diff --git a/packages/twenty-front/src/modules/views/components/ViewFieldsVisibleDropdownSection.tsx b/packages/twenty-front/src/modules/views/components/ViewFieldsVisibleDropdownSection.tsx index 072c4b582cf..aaaed9fc77e 100644 --- a/packages/twenty-front/src/modules/views/components/ViewFieldsVisibleDropdownSection.tsx +++ b/packages/twenty-front/src/modules/views/components/ViewFieldsVisibleDropdownSection.tsx @@ -10,6 +10,7 @@ import { visibleRecordFieldsComponentSelector } from '@/object-record/record-fie import { DraggableItem } from '@/ui/layout/draggable-list/components/DraggableItem'; import { DraggableList } from '@/ui/layout/draggable-list/components/DraggableList'; import { DropdownMenuItemsContainer } from '@/ui/layout/dropdown/components/DropdownMenuItemsContainer'; +import { dropdownYPositionComponentState } from '@/ui/layout/dropdown/states/internal/dropdownYPositionComponentState'; import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; import { ViewType } from '@/views/types/ViewType'; import { useContext } from 'react'; @@ -76,6 +77,10 @@ export const ViewFieldsVisibleDropdownSection = () => { ) .toSorted(sortByProperty('position')); + const dropdownYPosition = useRecoilComponentValue( + dropdownYPositionComponentState, + ); + return ( <> @@ -107,6 +112,8 @@ export const ViewFieldsVisibleDropdownSection = () => { key={recordField.fieldMetadataItemId} draggableId={recordField.fieldMetadataItemId} index={fieldIndex + 1} + isInsideScrollableContainer + containerOffsetY={dropdownYPosition} itemComponent={