Fixed dropdown bugs on 0.34 (#9000)

- New task dropdown wasn't using the proper dropdown id
- Action menu triggered by context menu (right click) on table cell was
listening in edit mode.
This commit is contained in:
Lucas Bordeau
2024-12-10 16:01:03 +01:00
committed by GitHub
parent b0595e452a
commit 013eda4a32
11 changed files with 62 additions and 29 deletions

View File

@ -21,10 +21,6 @@ type StyledContainerProps = {
const StyledContainerActionMenuDropdown = styled.div<StyledContainerProps>` const StyledContainerActionMenuDropdown = styled.div<StyledContainerProps>`
align-items: flex-start; align-items: flex-start;
background: ${({ theme }) => theme.background.secondary};
border: 1px solid ${({ theme }) => theme.border.color.light};
border-radius: ${({ theme }) => theme.border.radius.md};
box-shadow: ${({ theme }) => theme.boxShadow.strong};
display: flex; display: flex;
flex-direction: column; flex-direction: column;
@ -33,7 +29,8 @@ const StyledContainerActionMenuDropdown = styled.div<StyledContainerProps>`
top: ${(props) => `${props.position.y}px`}; top: ${(props) => `${props.position.y}px`};
transform: translateX(-50%); transform: translateX(-50%);
width: auto; width: 0;
height: 0;
`; `;
export const RecordIndexActionMenuDropdown = () => { export const RecordIndexActionMenuDropdown = () => {
@ -84,6 +81,7 @@ export const RecordIndexActionMenuDropdown = () => {
))} ))}
</DropdownMenuItemsContainer> </DropdownMenuItemsContainer>
} }
avoidPortal
/> />
</StyledContainerActionMenuDropdown> </StyledContainerActionMenuDropdown>
); );

View File

@ -47,7 +47,6 @@ export const FavoriteFolderNavigationDrawerItemDropdown = ({
dropdownHotkeyScope={{ dropdownHotkeyScope={{
scope: FavoriteFolderHotkeyScope.FavoriteFolderRightIconDropdown, scope: FavoriteFolderHotkeyScope.FavoriteFolderRightIconDropdown,
}} }}
usePortal
data-select-disable data-select-disable
clickableComponent={ clickableComponent={
<StyledIconContainer> <StyledIconContainer>

View File

@ -7,7 +7,6 @@ import { useFieldFocus } from '@/object-record/record-field/hooks/useFieldFocus'
import { CellHotkeyScopeContext } from '@/object-record/record-table/contexts/CellHotkeyScopeContext'; import { CellHotkeyScopeContext } from '@/object-record/record-table/contexts/CellHotkeyScopeContext';
import { RecordTableCellContext } from '@/object-record/record-table/contexts/RecordTableCellContext'; import { RecordTableCellContext } from '@/object-record/record-table/contexts/RecordTableCellContext';
import { RecordTableContext } from '@/object-record/record-table/contexts/RecordTableContext'; import { RecordTableContext } from '@/object-record/record-table/contexts/RecordTableContext';
import { RecordTableRowContext } from '@/object-record/record-table/contexts/RecordTableRowContext';
import { import {
DEFAULT_CELL_SCOPE, DEFAULT_CELL_SCOPE,
useOpenRecordTableCellFromCell, useOpenRecordTableCellFromCell,
@ -44,7 +43,6 @@ export const RecordTableCellBaseContainer = ({
const { setIsFocused } = useFieldFocus(); const { setIsFocused } = useFieldFocus();
const { openTableCell } = useOpenRecordTableCellFromCell(); const { openTableCell } = useOpenRecordTableCellFromCell();
const { theme } = useContext(ThemeContext); const { theme } = useContext(ThemeContext);
const { recordId } = useContext(RecordTableRowContext);
const { hasSoftFocus, cellPosition } = useContext(RecordTableCellContext); const { hasSoftFocus, cellPosition } = useContext(RecordTableCellContext);
@ -71,12 +69,6 @@ export const RecordTableCellBaseContainer = ({
} }
}; };
const { onActionMenuDropdownOpened } = useContext(RecordTableContext);
const handleActionMenuDropdown = (event: React.MouseEvent) => {
onActionMenuDropdownOpened(event, recordId);
};
const { hotkeyScope } = useContext(FieldContext); const { hotkeyScope } = useContext(FieldContext);
const editHotkeyScope = { scope: hotkeyScope ?? DEFAULT_CELL_SCOPE }; const editHotkeyScope = { scope: hotkeyScope ?? DEFAULT_CELL_SCOPE };
@ -87,7 +79,6 @@ export const RecordTableCellBaseContainer = ({
onMouseLeave={handleContainerMouseLeave} onMouseLeave={handleContainerMouseLeave}
onMouseMove={handleContainerMouseMove} onMouseMove={handleContainerMouseMove}
onClick={handleContainerClick} onClick={handleContainerClick}
onContextMenu={handleActionMenuDropdown}
backgroundColorTransparentSecondary={ backgroundColorTransparentSecondary={
theme.background.transparent.secondary theme.background.transparent.secondary
} }

View File

@ -26,6 +26,7 @@ export type EditableCellDisplayContainerProps = {
onClick?: () => void; onClick?: () => void;
scrollRef?: Ref<HTMLDivElement>; scrollRef?: Ref<HTMLDivElement>;
isHovered?: boolean; isHovered?: boolean;
onContextMenu?: (event: React.MouseEvent<HTMLDivElement, MouseEvent>) => void;
}; };
export const RecordTableCellDisplayContainer = ({ export const RecordTableCellDisplayContainer = ({
@ -33,6 +34,7 @@ export const RecordTableCellDisplayContainer = ({
softFocus, softFocus,
onClick, onClick,
scrollRef, scrollRef,
onContextMenu,
}: React.PropsWithChildren<EditableCellDisplayContainerProps>) => ( }: React.PropsWithChildren<EditableCellDisplayContainerProps>) => (
<StyledOuterContainer <StyledOuterContainer
data-testid={ data-testid={
@ -41,6 +43,7 @@ export const RecordTableCellDisplayContainer = ({
onClick={onClick} onClick={onClick}
ref={scrollRef} ref={scrollRef}
hasSoftFocus={softFocus} hasSoftFocus={softFocus}
onContextMenu={onContextMenu}
> >
<StyledInnerContainer>{children}</StyledInnerContainer> <StyledInnerContainer>{children}</StyledInnerContainer>
</StyledOuterContainer> </StyledOuterContainer>

View File

@ -1,19 +1,24 @@
import { useIsFieldEmpty } from '@/object-record/record-field/hooks/useIsFieldEmpty'; import { FieldContext } from '@/object-record/record-field/contexts/FieldContext';
import { RecordTableContext } from '@/object-record/record-table/contexts/RecordTableContext';
import { useContext } from 'react';
import { RecordTableCellDisplayContainer } from './RecordTableCellDisplayContainer'; import { RecordTableCellDisplayContainer } from './RecordTableCellDisplayContainer';
export const RecordTableCellDisplayMode = ({ export const RecordTableCellDisplayMode = ({
children, children,
softFocus, softFocus,
}: React.PropsWithChildren<{ softFocus?: boolean }>) => { }: React.PropsWithChildren<{ softFocus?: boolean }>) => {
const isEmpty = useIsFieldEmpty(); const { onActionMenuDropdownOpened } = useContext(RecordTableContext);
const { recordId } = useContext(FieldContext);
if (isEmpty) { const handleActionMenuDropdown = (event: React.MouseEvent) => {
return <></>; onActionMenuDropdownOpened(event, recordId);
} };
return ( return (
<RecordTableCellDisplayContainer softFocus={softFocus}> <RecordTableCellDisplayContainer
softFocus={softFocus}
onContextMenu={handleActionMenuDropdown}
>
{children} {children}
</RecordTableCellDisplayContainer> </RecordTableCellDisplayContainer>
); );

View File

@ -19,7 +19,9 @@ import { isDefined } from '~/utils/isDefined';
import { TableHotkeyScope } from '../../types/TableHotkeyScope'; import { TableHotkeyScope } from '../../types/TableHotkeyScope';
import { FieldContext } from '@/object-record/record-field/contexts/FieldContext';
import { useIsFieldValueReadOnly } from '@/object-record/record-field/hooks/useIsFieldValueReadOnly'; import { useIsFieldValueReadOnly } from '@/object-record/record-field/hooks/useIsFieldValueReadOnly';
import { RecordTableContext } from '@/object-record/record-table/contexts/RecordTableContext';
import { RecordTableCellDisplayContainer } from './RecordTableCellDisplayContainer'; import { RecordTableCellDisplayContainer } from './RecordTableCellDisplayContainer';
type RecordTableCellSoftFocusModeProps = { type RecordTableCellSoftFocusModeProps = {
@ -32,6 +34,7 @@ export const RecordTableCellSoftFocusMode = ({
nonEditModeContent, nonEditModeContent,
}: RecordTableCellSoftFocusModeProps) => { }: RecordTableCellSoftFocusModeProps) => {
const { columnIndex } = useContext(RecordTableCellContext); const { columnIndex } = useContext(RecordTableCellContext);
const { recordId } = useContext(FieldContext);
const isFieldReadOnly = useIsFieldValueReadOnly(); const isFieldReadOnly = useIsFieldValueReadOnly();
@ -132,6 +135,12 @@ export const RecordTableCellSoftFocusMode = ({
*/ */
}; };
const { onActionMenuDropdownOpened } = useContext(RecordTableContext);
const handleActionMenuDropdown = (event: React.MouseEvent) => {
onActionMenuDropdownOpened(event, recordId);
};
const isFirstColumn = columnIndex === 0; const isFirstColumn = columnIndex === 0;
const customButtonIcon = useGetButtonIcon(); const customButtonIcon = useGetButtonIcon();
const buttonIcon = isFirstColumn const buttonIcon = isFirstColumn
@ -152,6 +161,7 @@ export const RecordTableCellSoftFocusMode = ({
onClick={handleClick} onClick={handleClick}
scrollRef={scrollRef} scrollRef={scrollRef}
softFocus softFocus
onContextMenu={handleActionMenuDropdown}
> >
{dontShowContent ? ( {dontShowContent ? (
<></> <></>

View File

@ -6,6 +6,7 @@ import { getActionBarIdFromActionMenuId } from '@/action-menu/utils/getActionBar
import { getActionMenuDropdownIdFromActionMenuId } from '@/action-menu/utils/getActionMenuDropdownIdFromActionMenuId'; import { getActionMenuDropdownIdFromActionMenuId } from '@/action-menu/utils/getActionMenuDropdownIdFromActionMenuId';
import { isRowSelectedComponentFamilyState } from '@/object-record/record-table/record-table-row/states/isRowSelectedComponentFamilyState'; import { isRowSelectedComponentFamilyState } from '@/object-record/record-table/record-table-row/states/isRowSelectedComponentFamilyState';
import { isBottomBarOpenedComponentState } from '@/ui/layout/bottom-bar/states/isBottomBarOpenedComponentState'; import { isBottomBarOpenedComponentState } from '@/ui/layout/bottom-bar/states/isBottomBarOpenedComponentState';
import { useSetActiveDropdownFocusIdAndMemorizePrevious } from '@/ui/layout/dropdown/hooks/useSetFocusedDropdownIdAndMemorizePrevious';
import { isDropdownOpenComponentState } from '@/ui/layout/dropdown/states/isDropdownOpenComponentState'; import { isDropdownOpenComponentState } from '@/ui/layout/dropdown/states/isDropdownOpenComponentState';
import { getSnapshotValue } from '@/ui/utilities/recoil-scope/utils/getSnapshotValue'; import { getSnapshotValue } from '@/ui/utilities/recoil-scope/utils/getSnapshotValue';
import { useAvailableComponentInstanceIdOrThrow } from '@/ui/utilities/state/component-state/hooks/useAvailableComponentInstanceIdOrThrow'; import { useAvailableComponentInstanceIdOrThrow } from '@/ui/utilities/state/component-state/hooks/useAvailableComponentInstanceIdOrThrow';
@ -40,6 +41,9 @@ export const useTriggerActionMenuDropdown = ({
instanceId: getActionBarIdFromActionMenuId(actionMenuInstanceId), instanceId: getActionBarIdFromActionMenuId(actionMenuInstanceId),
}); });
const { setActiveDropdownFocusIdAndMemorizePrevious } =
useSetActiveDropdownFocusIdAndMemorizePrevious();
const triggerActionMenuDropdown = useRecoilCallback( const triggerActionMenuDropdown = useRecoilCallback(
({ set, snapshot }) => ({ set, snapshot }) =>
(event: React.MouseEvent, recordId: string) => { (event: React.MouseEvent, recordId: string) => {
@ -61,12 +65,19 @@ export const useTriggerActionMenuDropdown = ({
set(isActionBarOpenState, false); set(isActionBarOpenState, false);
set(isActionMenuDropdownOpenState, true); set(isActionMenuDropdownOpenState, true);
const actionMenuDropdownId =
getActionMenuDropdownIdFromActionMenuId(actionMenuInstanceId);
setActiveDropdownFocusIdAndMemorizePrevious(actionMenuDropdownId);
}, },
[ [
isActionBarOpenState, isActionBarOpenState,
isActionMenuDropdownOpenState, isActionMenuDropdownOpenState,
isRowSelectedFamilyState, isRowSelectedFamilyState,
recordIndexActionMenuDropdownPositionState, recordIndexActionMenuDropdownPositionState,
setActiveDropdownFocusIdAndMemorizePrevious,
actionMenuInstanceId,
], ],
); );

View File

@ -47,7 +47,6 @@ export const RecordTableColumnHeadWithDropdown = ({
clickableComponent={<RecordTableColumnHead column={column} />} clickableComponent={<RecordTableColumnHead column={column} />}
dropdownComponents={<RecordTableColumnHeadDropdownMenu column={column} />} dropdownComponents={<RecordTableColumnHeadDropdownMenu column={column} />}
dropdownOffset={{ x: -1 }} dropdownOffset={{ x: -1 }}
usePortal
dropdownPlacement="bottom-start" dropdownPlacement="bottom-start"
dropdownHotkeyScope={{ scope: column.fieldMetadataId + '-header' }} dropdownHotkeyScope={{ scope: column.fieldMetadataId + '-header' }}
/> />

View File

@ -39,9 +39,9 @@ type DropdownProps = {
dropdownStrategy?: 'fixed' | 'absolute'; dropdownStrategy?: 'fixed' | 'absolute';
disableBlur?: boolean; disableBlur?: boolean;
onClickOutside?: () => void; onClickOutside?: () => void;
usePortal?: boolean;
onClose?: () => void; onClose?: () => void;
onOpen?: () => void; onOpen?: () => void;
avoidPortal?: boolean;
}; };
export const Dropdown = ({ export const Dropdown = ({
@ -59,6 +59,7 @@ export const Dropdown = ({
onClickOutside, onClickOutside,
onClose, onClose,
onOpen, onOpen,
avoidPortal,
}: DropdownProps) => { }: DropdownProps) => {
const { isDropdownOpen, toggleDropdown } = useDropdown(dropdownId); const { isDropdownOpen, toggleDropdown } = useDropdown(dropdownId);
@ -132,6 +133,7 @@ export const Dropdown = ({
hotkey={hotkey} hotkey={hotkey}
onClickOutside={onClickOutside} onClickOutside={onClickOutside}
onHotkeyTriggered={toggleDropdown} onHotkeyTriggered={toggleDropdown}
avoidPortal={avoidPortal}
/> />
)} )}
<DropdownOnToggleEffect <DropdownOnToggleEffect

View File

@ -36,6 +36,7 @@ export type DropdownContentProps = {
dropdownMenuWidth?: `${string}px` | `${number}%` | 'auto' | number; dropdownMenuWidth?: `${string}px` | `${number}%` | 'auto' | number;
dropdownComponents: React.ReactNode; dropdownComponents: React.ReactNode;
parentDropdownId?: string; parentDropdownId?: string;
avoidPortal?: boolean;
}; };
export const DropdownContent = ({ export const DropdownContent = ({
@ -51,6 +52,7 @@ export const DropdownContent = ({
disableBlur, disableBlur,
dropdownMenuWidth, dropdownMenuWidth,
dropdownComponents, dropdownComponents,
avoidPortal,
}: DropdownContentProps) => { }: DropdownContentProps) => {
const { isDropdownOpen, closeDropdown, dropdownWidth, setDropdownPlacement } = const { isDropdownOpen, closeDropdown, dropdownWidth, setDropdownPlacement } =
useDropdown(dropdownId); useDropdown(dropdownId);
@ -111,7 +113,7 @@ export const DropdownContent = ({
{hotkey && onHotkeyTriggered && ( {hotkey && onHotkeyTriggered && (
<HotkeyEffect hotkey={hotkey} onHotkeyTriggered={onHotkeyTriggered} /> <HotkeyEffect hotkey={hotkey} onHotkeyTriggered={onHotkeyTriggered} />
)} )}
<FloatingPortal> {avoidPortal ? (
<DropdownMenu <DropdownMenu
className={className} className={className}
disableBlur={disableBlur} disableBlur={disableBlur}
@ -122,7 +124,20 @@ export const DropdownContent = ({
> >
{dropdownComponents} {dropdownComponents}
</DropdownMenu> </DropdownMenu>
</FloatingPortal> ) : (
<FloatingPortal>
<DropdownMenu
className={className}
disableBlur={disableBlur}
width={dropdownMenuWidth ?? dropdownWidth}
data-select-disable
ref={floatingUiRefs.setFloating}
style={dropdownMenuStyles}
>
{dropdownComponents}
</DropdownMenu>
</FloatingPortal>
)}
</> </>
); );
}; };

View File

@ -30,7 +30,8 @@ export const ShowPageAddButton = ({
}: { }: {
activityTargetObject: ActivityTargetableObject; activityTargetObject: ActivityTargetableObject;
}) => { }) => {
const { closeDropdown } = useDropdown('add-show-page'); const { closeDropdown } = useDropdown(SHOW_PAGE_ADD_BUTTON_DROPDOWN_ID);
const openNote = useOpenCreateActivityDrawer({ const openNote = useOpenCreateActivityDrawer({
activityObjectNameSingular: CoreObjectNameSingular.Note, activityObjectNameSingular: CoreObjectNameSingular.Note,
}); });
@ -43,8 +44,7 @@ export const ShowPageAddButton = ({
openNote({ openNote({
targetableObjects: [activityTargetObject], targetableObjects: [activityTargetObject],
}); });
} } else if (objectNameSingular === CoreObjectNameSingular.Task) {
if (objectNameSingular === CoreObjectNameSingular.Task) {
openTask({ openTask({
targetableObjects: [activityTargetObject], targetableObjects: [activityTargetObject],
}); });