Proposal Date picker overflow (#4996)

Unfortunately, it is not possible in CSS to have an overflow:visible
over x-axis while having an overflow:hidden over y-axis, leading to the
following issue:

<img width="1512" alt="image"
src="https://github.com/twentyhq/twenty/assets/12035771/9b84cbbb-c6c4-4fd6-a630-a24f01eccf73">

I'm refactoring the RecordInlineCell and RecordTableCell to use
useFloating + createPortal to open the cell.
This commit is contained in:
Charles Bochet
2024-04-17 11:35:45 +02:00
committed by GitHub
parent 340af9a244
commit 67db7d85c0
14 changed files with 154 additions and 161 deletions

View File

@ -1,7 +1,6 @@
import { useAddressField } from '@/object-record/record-field/meta-types/hooks/useAddressField';
import { FieldAddressDraftValue } from '@/object-record/record-field/types/FieldInputDraftValue';
import { AddressInput } from '@/ui/field/input/components/AddressInput';
import { FieldInputOverlay } from '@/ui/field/input/components/FieldInputOverlay';
import { usePersistField } from '../../../hooks/usePersistField';
@ -69,17 +68,15 @@ export const AddressFieldInput = ({
};
return (
<FieldInputOverlay>
<AddressInput
value={convertToAddress(draftValue)}
onClickOutside={handleClickOutside}
onEnter={handleEnter}
onEscape={handleEscape}
hotkeyScope={hotkeyScope}
onChange={handleChange}
onTab={handleTab}
onShiftTab={handleShiftTab}
/>
</FieldInputOverlay>
<AddressInput
value={convertToAddress(draftValue)}
onClickOutside={handleClickOutside}
onEnter={handleEnter}
onEscape={handleEscape}
hotkeyScope={hotkeyScope}
onChange={handleChange}
onTab={handleTab}
onShiftTab={handleShiftTab}
/>
);
};

View File

@ -72,7 +72,6 @@ const StyledInlineCellBaseContainer = styled.div`
gap: ${({ theme }) => theme.spacing(1)};
position: relative;
user-select: none;
`;

View File

@ -1,4 +1,6 @@
import { createPortal } from 'react-dom';
import styled from '@emotion/styled';
import { autoUpdate, flip, offset, useFloating } from '@floating-ui/react';
const StyledInlineCellEditModeContainer = styled.div<RecordInlineCellEditModeProps>`
align-items: center;
@ -7,7 +9,6 @@ const StyledInlineCellEditModeContainer = styled.div<RecordInlineCellEditModePro
height: 24px;
margin-left: -${({ theme }) => theme.spacing(1)};
position: relative;
z-index: 10;
`;
@ -28,8 +29,24 @@ type RecordInlineCellEditModeProps = {
export const RecordInlineCellEditMode = ({
children,
}: RecordInlineCellEditModeProps) => (
<StyledInlineCellEditModeContainer data-testid="inline-cell-edit-mode-container">
<StyledInlineCellInput>{children}</StyledInlineCellInput>
</StyledInlineCellEditModeContainer>
);
}: RecordInlineCellEditModeProps) => {
const { refs, floatingStyles } = useFloating({
placement: 'right',
middleware: [flip(), offset(-1)],
whileElementsMounted: autoUpdate,
});
return (
<StyledInlineCellEditModeContainer
ref={refs.setReference}
data-testid="inline-cell-edit-mode-container"
>
{createPortal(
<StyledInlineCellInput ref={refs.setFloating} style={floatingStyles}>
{children}
</StyledInlineCellInput>,
document.body,
)}
</StyledInlineCellEditModeContainer>
);
};

View File

@ -7,7 +7,6 @@ interface PropertyBoxProps {
export const StyledPropertyBoxContainer = styled.div`
align-self: stretch;
background: ${({ theme }) => theme.background.secondary};
border-radius: ${({ theme }) => theme.border.radius.sm};
display: flex;
flex-direction: column;

View File

@ -1,12 +1,11 @@
import { Key } from 'ts-key-enum';
import { SOFT_FOCUS_CLICK_OUTSIDE_LISTENER_ID } from '@/object-record/record-table/constants/SoftFocusClickOutsideListenerId';
import { useRecordTable } from '@/object-record/record-table/hooks/useRecordTable';
import { TableHotkeyScope } from '@/object-record/record-table/types/TableHotkeyScope';
import { useScopedHotkeys } from '@/ui/utilities/hotkey/hooks/useScopedHotkeys';
import {
useListenClickOutside,
useListenClickOutsideByClassName,
} from '@/ui/utilities/pointer-event/hooks/useListenClickOutside';
import { useClickOutsideListener } from '@/ui/utilities/pointer-event/hooks/useClickOutsideListener';
import { useListenClickOutsideByClassName } from '@/ui/utilities/pointer-event/hooks/useListenClickOutside';
type RecordTableInternalEffectProps = {
recordTableId: string;
@ -22,6 +21,10 @@ export const RecordTableInternalEffect = ({
useMapKeyboardToSoftFocus();
const { useListenClickOutside } = useClickOutsideListener(
SOFT_FOCUS_CLICK_OUTSIDE_LISTENER_ID,
);
useListenClickOutside({
refs: [tableBodyRef],
callback: () => {

View File

@ -29,10 +29,6 @@ import { useRecordTable } from '../hooks/useRecordTable';
import { RecordTableInternalEffect } from './RecordTableInternalEffect';
const StyledTableWithHeader = styled.div`
display: flex;
flex: 1;
flex-direction: column;
width: 100%;
height: 100%;
`;

View File

@ -0,0 +1,2 @@
export const SOFT_FOCUS_CLICK_OUTSIDE_LISTENER_ID =
'soft-focus-click-outside-listener-id';

View File

@ -48,8 +48,6 @@ const StyledCellBaseContainer = styled.div`
export type RecordTableCellContainerProps = {
editModeContent: ReactElement;
nonEditModeContent: ReactElement;
editModeHorizontalAlign?: 'left' | 'right';
editModeVerticalPosition?: 'over' | 'below';
editHotkeyScope?: HotkeyScope;
transparent?: boolean;
maxContentWidth?: number;
@ -62,8 +60,6 @@ const DEFAULT_CELL_SCOPE: HotkeyScope = {
};
export const RecordTableCellContainer = ({
editModeHorizontalAlign = 'left',
editModeVerticalPosition = 'over',
editModeContent,
nonEditModeContent,
editHotkeyScope,
@ -163,12 +159,7 @@ export const RecordTableCellContainer = ({
onMouseLeave={handleContainerMouseLeave}
>
{isCurrentTableCellInEditMode ? (
<RecordTableCellEditMode
editModeHorizontalAlign={editModeHorizontalAlign}
editModeVerticalPosition={editModeVerticalPosition}
>
{editModeContent}
</RecordTableCellEditMode>
<RecordTableCellEditMode>{editModeContent}</RecordTableCellEditMode>
) : hasSoftFocus ? (
<>
{showButton && (

View File

@ -1,5 +1,7 @@
import { ReactElement } from 'react';
import { createPortal } from 'react-dom';
import styled from '@emotion/styled';
import { autoUpdate, flip, offset, useFloating } from '@floating-ui/react';
const StyledEditableCellEditModeContainer = styled.div<RecordTableCellEditModeProps>`
align-items: center;
@ -7,27 +9,46 @@ const StyledEditableCellEditModeContainer = styled.div<RecordTableCellEditModePr
min-width: 200px;
width: calc(100% + 2px);
z-index: 1;
height: 100%;
`;
const StyledTableCellInput = styled.div`
align-items: center;
display: flex;
min-height: 32px;
min-width: 200px;
z-index: 10;
`;
export type RecordTableCellEditModeProps = {
children: ReactElement;
transparent?: boolean;
maxContentWidth?: number;
editModeHorizontalAlign?: 'left' | 'right';
editModeVerticalPosition?: 'over' | 'below';
initialValue?: string;
};
export const RecordTableCellEditMode = ({
editModeHorizontalAlign,
editModeVerticalPosition,
children,
}: RecordTableCellEditModeProps) => (
<StyledEditableCellEditModeContainer
data-testid="editable-cell-edit-mode-container"
editModeHorizontalAlign={editModeHorizontalAlign}
editModeVerticalPosition={editModeVerticalPosition}
>
{children}
</StyledEditableCellEditModeContainer>
);
}: RecordTableCellEditModeProps) => {
const { refs, floatingStyles } = useFloating({
placement: 'top-start',
middleware: [flip(), offset(-32)],
whileElementsMounted: autoUpdate,
});
return (
<StyledEditableCellEditModeContainer
ref={refs.setReference}
data-testid="editable-cell-edit-mode-container"
>
{createPortal(
<StyledTableCellInput ref={refs.setFloating} style={floatingStyles}>
{children}
</StyledTableCellInput>,
document.body,
)}
</StyledEditableCellEditModeContainer>
);
};

View File

@ -1,8 +1,10 @@
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';
@ -12,11 +14,16 @@ export const useCloseRecordTableCell = () => {
const { setDragSelectionStartEnabled } = useDragSelect();
const { pendingRecordIdState } = useRecordTableStates();
const { toggleClickOutsideListener } = useClickOutsideListener(
SOFT_FOCUS_CLICK_OUTSIDE_LISTENER_ID,
);
const closeCurrentTableCellInEditMode = useCloseCurrentTableCellInEditMode();
const resetRecordTablePendingRecordId =
useResetRecoilState(pendingRecordIdState);
const closeTableCell = async () => {
toggleClickOutsideListener(true);
setDragSelectionStartEnabled(true);
closeCurrentTableCellInEditMode();
setHotkeyScope(TableHotkeyScope.TableSoftFocus);

View File

@ -5,12 +5,14 @@ import { useRecoilCallback } from 'recoil';
import { FieldContext } from '@/object-record/record-field/contexts/FieldContext';
import { useIsFieldEmpty } from '@/object-record/record-field/hooks/useIsFieldEmpty';
import { useRecordFieldInput } from '@/object-record/record-field/hooks/useRecordFieldInput';
import { SOFT_FOCUS_CLICK_OUTSIDE_LISTENER_ID } from '@/object-record/record-table/constants/SoftFocusClickOutsideListenerId';
import { RecordTableCellContext } from '@/object-record/record-table/contexts/RecordTableCellContext';
import { RecordTableRowContext } from '@/object-record/record-table/contexts/RecordTableRowContext';
import { useLeaveTableFocus } from '@/object-record/record-table/hooks/internal/useLeaveTableFocus';
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 { isDefined } from '~/utils/isDefined';
import { CellHotkeyScopeContext } from '../../contexts/CellHotkeyScopeContext';
@ -33,6 +35,9 @@ export const useOpenRecordTableCell = () => {
const navigate = useNavigate();
const leaveTableFocus = useLeaveTableFocus();
const { toggleClickOutsideListener } = useClickOutsideListener(
SOFT_FOCUS_CLICK_OUTSIDE_LISTENER_ID,
);
const { columnIndex } = useContext(RecordTableCellContext);
const isFirstColumnCell = columnIndex === 0;
@ -60,6 +65,7 @@ export const useOpenRecordTableCell = () => {
setCurrentTableCellInEditMode();
initFieldInputDraftValue(options?.initialValue);
toggleClickOutsideListener(false);
if (isDefined(customCellHotkeyScope)) {
setHotkeyScope(
@ -80,6 +86,7 @@ export const useOpenRecordTableCell = () => {
setDragSelectionStartEnabled,
setCurrentTableCellInEditMode,
initFieldInputDraftValue,
toggleClickOutsideListener,
customCellHotkeyScope,
leaveTableFocus,
navigate,