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:
@ -1,7 +1,6 @@
|
|||||||
import { useAddressField } from '@/object-record/record-field/meta-types/hooks/useAddressField';
|
import { useAddressField } from '@/object-record/record-field/meta-types/hooks/useAddressField';
|
||||||
import { FieldAddressDraftValue } from '@/object-record/record-field/types/FieldInputDraftValue';
|
import { FieldAddressDraftValue } from '@/object-record/record-field/types/FieldInputDraftValue';
|
||||||
import { AddressInput } from '@/ui/field/input/components/AddressInput';
|
import { AddressInput } from '@/ui/field/input/components/AddressInput';
|
||||||
import { FieldInputOverlay } from '@/ui/field/input/components/FieldInputOverlay';
|
|
||||||
|
|
||||||
import { usePersistField } from '../../../hooks/usePersistField';
|
import { usePersistField } from '../../../hooks/usePersistField';
|
||||||
|
|
||||||
@ -69,17 +68,15 @@ export const AddressFieldInput = ({
|
|||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<FieldInputOverlay>
|
<AddressInput
|
||||||
<AddressInput
|
value={convertToAddress(draftValue)}
|
||||||
value={convertToAddress(draftValue)}
|
onClickOutside={handleClickOutside}
|
||||||
onClickOutside={handleClickOutside}
|
onEnter={handleEnter}
|
||||||
onEnter={handleEnter}
|
onEscape={handleEscape}
|
||||||
onEscape={handleEscape}
|
hotkeyScope={hotkeyScope}
|
||||||
hotkeyScope={hotkeyScope}
|
onChange={handleChange}
|
||||||
onChange={handleChange}
|
onTab={handleTab}
|
||||||
onTab={handleTab}
|
onShiftTab={handleShiftTab}
|
||||||
onShiftTab={handleShiftTab}
|
/>
|
||||||
/>
|
|
||||||
</FieldInputOverlay>
|
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@ -72,7 +72,6 @@ const StyledInlineCellBaseContainer = styled.div`
|
|||||||
|
|
||||||
gap: ${({ theme }) => theme.spacing(1)};
|
gap: ${({ theme }) => theme.spacing(1)};
|
||||||
|
|
||||||
position: relative;
|
|
||||||
user-select: none;
|
user-select: none;
|
||||||
`;
|
`;
|
||||||
|
|
||||||
|
|||||||
@ -1,4 +1,6 @@
|
|||||||
|
import { createPortal } from 'react-dom';
|
||||||
import styled from '@emotion/styled';
|
import styled from '@emotion/styled';
|
||||||
|
import { autoUpdate, flip, offset, useFloating } from '@floating-ui/react';
|
||||||
|
|
||||||
const StyledInlineCellEditModeContainer = styled.div<RecordInlineCellEditModeProps>`
|
const StyledInlineCellEditModeContainer = styled.div<RecordInlineCellEditModeProps>`
|
||||||
align-items: center;
|
align-items: center;
|
||||||
@ -7,7 +9,6 @@ const StyledInlineCellEditModeContainer = styled.div<RecordInlineCellEditModePro
|
|||||||
height: 24px;
|
height: 24px;
|
||||||
|
|
||||||
margin-left: -${({ theme }) => theme.spacing(1)};
|
margin-left: -${({ theme }) => theme.spacing(1)};
|
||||||
position: relative;
|
|
||||||
z-index: 10;
|
z-index: 10;
|
||||||
`;
|
`;
|
||||||
|
|
||||||
@ -28,8 +29,24 @@ type RecordInlineCellEditModeProps = {
|
|||||||
|
|
||||||
export const RecordInlineCellEditMode = ({
|
export const RecordInlineCellEditMode = ({
|
||||||
children,
|
children,
|
||||||
}: RecordInlineCellEditModeProps) => (
|
}: RecordInlineCellEditModeProps) => {
|
||||||
<StyledInlineCellEditModeContainer data-testid="inline-cell-edit-mode-container">
|
const { refs, floatingStyles } = useFloating({
|
||||||
<StyledInlineCellInput>{children}</StyledInlineCellInput>
|
placement: 'right',
|
||||||
</StyledInlineCellEditModeContainer>
|
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>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|||||||
@ -7,7 +7,6 @@ interface PropertyBoxProps {
|
|||||||
|
|
||||||
export const StyledPropertyBoxContainer = styled.div`
|
export const StyledPropertyBoxContainer = styled.div`
|
||||||
align-self: stretch;
|
align-self: stretch;
|
||||||
background: ${({ theme }) => theme.background.secondary};
|
|
||||||
border-radius: ${({ theme }) => theme.border.radius.sm};
|
border-radius: ${({ theme }) => theme.border.radius.sm};
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
|
|||||||
@ -1,12 +1,11 @@
|
|||||||
import { Key } from 'ts-key-enum';
|
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 { useRecordTable } from '@/object-record/record-table/hooks/useRecordTable';
|
||||||
import { TableHotkeyScope } from '@/object-record/record-table/types/TableHotkeyScope';
|
import { TableHotkeyScope } from '@/object-record/record-table/types/TableHotkeyScope';
|
||||||
import { useScopedHotkeys } from '@/ui/utilities/hotkey/hooks/useScopedHotkeys';
|
import { useScopedHotkeys } from '@/ui/utilities/hotkey/hooks/useScopedHotkeys';
|
||||||
import {
|
import { useClickOutsideListener } from '@/ui/utilities/pointer-event/hooks/useClickOutsideListener';
|
||||||
useListenClickOutside,
|
import { useListenClickOutsideByClassName } from '@/ui/utilities/pointer-event/hooks/useListenClickOutside';
|
||||||
useListenClickOutsideByClassName,
|
|
||||||
} from '@/ui/utilities/pointer-event/hooks/useListenClickOutside';
|
|
||||||
|
|
||||||
type RecordTableInternalEffectProps = {
|
type RecordTableInternalEffectProps = {
|
||||||
recordTableId: string;
|
recordTableId: string;
|
||||||
@ -22,6 +21,10 @@ export const RecordTableInternalEffect = ({
|
|||||||
|
|
||||||
useMapKeyboardToSoftFocus();
|
useMapKeyboardToSoftFocus();
|
||||||
|
|
||||||
|
const { useListenClickOutside } = useClickOutsideListener(
|
||||||
|
SOFT_FOCUS_CLICK_OUTSIDE_LISTENER_ID,
|
||||||
|
);
|
||||||
|
|
||||||
useListenClickOutside({
|
useListenClickOutside({
|
||||||
refs: [tableBodyRef],
|
refs: [tableBodyRef],
|
||||||
callback: () => {
|
callback: () => {
|
||||||
|
|||||||
@ -29,10 +29,6 @@ import { useRecordTable } from '../hooks/useRecordTable';
|
|||||||
import { RecordTableInternalEffect } from './RecordTableInternalEffect';
|
import { RecordTableInternalEffect } from './RecordTableInternalEffect';
|
||||||
|
|
||||||
const StyledTableWithHeader = styled.div`
|
const StyledTableWithHeader = styled.div`
|
||||||
display: flex;
|
|
||||||
flex: 1;
|
|
||||||
flex-direction: column;
|
|
||||||
width: 100%;
|
|
||||||
height: 100%;
|
height: 100%;
|
||||||
`;
|
`;
|
||||||
|
|
||||||
|
|||||||
@ -0,0 +1,2 @@
|
|||||||
|
export const SOFT_FOCUS_CLICK_OUTSIDE_LISTENER_ID =
|
||||||
|
'soft-focus-click-outside-listener-id';
|
||||||
@ -48,8 +48,6 @@ const StyledCellBaseContainer = styled.div`
|
|||||||
export type RecordTableCellContainerProps = {
|
export type RecordTableCellContainerProps = {
|
||||||
editModeContent: ReactElement;
|
editModeContent: ReactElement;
|
||||||
nonEditModeContent: ReactElement;
|
nonEditModeContent: ReactElement;
|
||||||
editModeHorizontalAlign?: 'left' | 'right';
|
|
||||||
editModeVerticalPosition?: 'over' | 'below';
|
|
||||||
editHotkeyScope?: HotkeyScope;
|
editHotkeyScope?: HotkeyScope;
|
||||||
transparent?: boolean;
|
transparent?: boolean;
|
||||||
maxContentWidth?: number;
|
maxContentWidth?: number;
|
||||||
@ -62,8 +60,6 @@ const DEFAULT_CELL_SCOPE: HotkeyScope = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export const RecordTableCellContainer = ({
|
export const RecordTableCellContainer = ({
|
||||||
editModeHorizontalAlign = 'left',
|
|
||||||
editModeVerticalPosition = 'over',
|
|
||||||
editModeContent,
|
editModeContent,
|
||||||
nonEditModeContent,
|
nonEditModeContent,
|
||||||
editHotkeyScope,
|
editHotkeyScope,
|
||||||
@ -163,12 +159,7 @@ export const RecordTableCellContainer = ({
|
|||||||
onMouseLeave={handleContainerMouseLeave}
|
onMouseLeave={handleContainerMouseLeave}
|
||||||
>
|
>
|
||||||
{isCurrentTableCellInEditMode ? (
|
{isCurrentTableCellInEditMode ? (
|
||||||
<RecordTableCellEditMode
|
<RecordTableCellEditMode>{editModeContent}</RecordTableCellEditMode>
|
||||||
editModeHorizontalAlign={editModeHorizontalAlign}
|
|
||||||
editModeVerticalPosition={editModeVerticalPosition}
|
|
||||||
>
|
|
||||||
{editModeContent}
|
|
||||||
</RecordTableCellEditMode>
|
|
||||||
) : hasSoftFocus ? (
|
) : hasSoftFocus ? (
|
||||||
<>
|
<>
|
||||||
{showButton && (
|
{showButton && (
|
||||||
|
|||||||
@ -1,5 +1,7 @@
|
|||||||
import { ReactElement } from 'react';
|
import { ReactElement } from 'react';
|
||||||
|
import { createPortal } from 'react-dom';
|
||||||
import styled from '@emotion/styled';
|
import styled from '@emotion/styled';
|
||||||
|
import { autoUpdate, flip, offset, useFloating } from '@floating-ui/react';
|
||||||
|
|
||||||
const StyledEditableCellEditModeContainer = styled.div<RecordTableCellEditModeProps>`
|
const StyledEditableCellEditModeContainer = styled.div<RecordTableCellEditModeProps>`
|
||||||
align-items: center;
|
align-items: center;
|
||||||
@ -7,27 +9,46 @@ const StyledEditableCellEditModeContainer = styled.div<RecordTableCellEditModePr
|
|||||||
min-width: 200px;
|
min-width: 200px;
|
||||||
width: calc(100% + 2px);
|
width: calc(100% + 2px);
|
||||||
z-index: 1;
|
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 = {
|
export type RecordTableCellEditModeProps = {
|
||||||
children: ReactElement;
|
children: ReactElement;
|
||||||
transparent?: boolean;
|
transparent?: boolean;
|
||||||
maxContentWidth?: number;
|
maxContentWidth?: number;
|
||||||
editModeHorizontalAlign?: 'left' | 'right';
|
|
||||||
editModeVerticalPosition?: 'over' | 'below';
|
|
||||||
initialValue?: string;
|
initialValue?: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const RecordTableCellEditMode = ({
|
export const RecordTableCellEditMode = ({
|
||||||
editModeHorizontalAlign,
|
|
||||||
editModeVerticalPosition,
|
|
||||||
children,
|
children,
|
||||||
}: RecordTableCellEditModeProps) => (
|
}: RecordTableCellEditModeProps) => {
|
||||||
<StyledEditableCellEditModeContainer
|
const { refs, floatingStyles } = useFloating({
|
||||||
data-testid="editable-cell-edit-mode-container"
|
placement: 'top-start',
|
||||||
editModeHorizontalAlign={editModeHorizontalAlign}
|
middleware: [flip(), offset(-32)],
|
||||||
editModeVerticalPosition={editModeVerticalPosition}
|
whileElementsMounted: autoUpdate,
|
||||||
>
|
});
|
||||||
{children}
|
|
||||||
</StyledEditableCellEditModeContainer>
|
return (
|
||||||
);
|
<StyledEditableCellEditModeContainer
|
||||||
|
ref={refs.setReference}
|
||||||
|
data-testid="editable-cell-edit-mode-container"
|
||||||
|
>
|
||||||
|
{createPortal(
|
||||||
|
<StyledTableCellInput ref={refs.setFloating} style={floatingStyles}>
|
||||||
|
{children}
|
||||||
|
</StyledTableCellInput>,
|
||||||
|
document.body,
|
||||||
|
)}
|
||||||
|
</StyledEditableCellEditModeContainer>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|||||||
@ -1,8 +1,10 @@
|
|||||||
import { useResetRecoilState } from 'recoil';
|
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 { useRecordTableStates } from '@/object-record/record-table/hooks/internal/useRecordTableStates';
|
||||||
import { useDragSelect } from '@/ui/utilities/drag-select/hooks/useDragSelect';
|
import { useDragSelect } from '@/ui/utilities/drag-select/hooks/useDragSelect';
|
||||||
import { useSetHotkeyScope } from '@/ui/utilities/hotkey/hooks/useSetHotkeyScope';
|
import { useSetHotkeyScope } from '@/ui/utilities/hotkey/hooks/useSetHotkeyScope';
|
||||||
|
import { useClickOutsideListener } from '@/ui/utilities/pointer-event/hooks/useClickOutsideListener';
|
||||||
|
|
||||||
import { useCloseCurrentTableCellInEditMode } from '../../hooks/internal/useCloseCurrentTableCellInEditMode';
|
import { useCloseCurrentTableCellInEditMode } from '../../hooks/internal/useCloseCurrentTableCellInEditMode';
|
||||||
import { TableHotkeyScope } from '../../types/TableHotkeyScope';
|
import { TableHotkeyScope } from '../../types/TableHotkeyScope';
|
||||||
@ -12,11 +14,16 @@ export const useCloseRecordTableCell = () => {
|
|||||||
const { setDragSelectionStartEnabled } = useDragSelect();
|
const { setDragSelectionStartEnabled } = useDragSelect();
|
||||||
const { pendingRecordIdState } = useRecordTableStates();
|
const { pendingRecordIdState } = useRecordTableStates();
|
||||||
|
|
||||||
|
const { toggleClickOutsideListener } = useClickOutsideListener(
|
||||||
|
SOFT_FOCUS_CLICK_OUTSIDE_LISTENER_ID,
|
||||||
|
);
|
||||||
|
|
||||||
const closeCurrentTableCellInEditMode = useCloseCurrentTableCellInEditMode();
|
const closeCurrentTableCellInEditMode = useCloseCurrentTableCellInEditMode();
|
||||||
const resetRecordTablePendingRecordId =
|
const resetRecordTablePendingRecordId =
|
||||||
useResetRecoilState(pendingRecordIdState);
|
useResetRecoilState(pendingRecordIdState);
|
||||||
|
|
||||||
const closeTableCell = async () => {
|
const closeTableCell = async () => {
|
||||||
|
toggleClickOutsideListener(true);
|
||||||
setDragSelectionStartEnabled(true);
|
setDragSelectionStartEnabled(true);
|
||||||
closeCurrentTableCellInEditMode();
|
closeCurrentTableCellInEditMode();
|
||||||
setHotkeyScope(TableHotkeyScope.TableSoftFocus);
|
setHotkeyScope(TableHotkeyScope.TableSoftFocus);
|
||||||
|
|||||||
@ -5,12 +5,14 @@ import { useRecoilCallback } from 'recoil';
|
|||||||
import { FieldContext } from '@/object-record/record-field/contexts/FieldContext';
|
import { FieldContext } from '@/object-record/record-field/contexts/FieldContext';
|
||||||
import { useIsFieldEmpty } from '@/object-record/record-field/hooks/useIsFieldEmpty';
|
import { useIsFieldEmpty } from '@/object-record/record-field/hooks/useIsFieldEmpty';
|
||||||
import { useRecordFieldInput } from '@/object-record/record-field/hooks/useRecordFieldInput';
|
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 { RecordTableCellContext } from '@/object-record/record-table/contexts/RecordTableCellContext';
|
||||||
import { RecordTableRowContext } from '@/object-record/record-table/contexts/RecordTableRowContext';
|
import { RecordTableRowContext } from '@/object-record/record-table/contexts/RecordTableRowContext';
|
||||||
import { useLeaveTableFocus } from '@/object-record/record-table/hooks/internal/useLeaveTableFocus';
|
import { useLeaveTableFocus } from '@/object-record/record-table/hooks/internal/useLeaveTableFocus';
|
||||||
import { useDragSelect } from '@/ui/utilities/drag-select/hooks/useDragSelect';
|
import { useDragSelect } from '@/ui/utilities/drag-select/hooks/useDragSelect';
|
||||||
import { useSetHotkeyScope } from '@/ui/utilities/hotkey/hooks/useSetHotkeyScope';
|
import { useSetHotkeyScope } from '@/ui/utilities/hotkey/hooks/useSetHotkeyScope';
|
||||||
import { HotkeyScope } from '@/ui/utilities/hotkey/types/HotkeyScope';
|
import { HotkeyScope } from '@/ui/utilities/hotkey/types/HotkeyScope';
|
||||||
|
import { useClickOutsideListener } from '@/ui/utilities/pointer-event/hooks/useClickOutsideListener';
|
||||||
import { isDefined } from '~/utils/isDefined';
|
import { isDefined } from '~/utils/isDefined';
|
||||||
|
|
||||||
import { CellHotkeyScopeContext } from '../../contexts/CellHotkeyScopeContext';
|
import { CellHotkeyScopeContext } from '../../contexts/CellHotkeyScopeContext';
|
||||||
@ -33,6 +35,9 @@ export const useOpenRecordTableCell = () => {
|
|||||||
|
|
||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
const leaveTableFocus = useLeaveTableFocus();
|
const leaveTableFocus = useLeaveTableFocus();
|
||||||
|
const { toggleClickOutsideListener } = useClickOutsideListener(
|
||||||
|
SOFT_FOCUS_CLICK_OUTSIDE_LISTENER_ID,
|
||||||
|
);
|
||||||
|
|
||||||
const { columnIndex } = useContext(RecordTableCellContext);
|
const { columnIndex } = useContext(RecordTableCellContext);
|
||||||
const isFirstColumnCell = columnIndex === 0;
|
const isFirstColumnCell = columnIndex === 0;
|
||||||
@ -60,6 +65,7 @@ export const useOpenRecordTableCell = () => {
|
|||||||
setCurrentTableCellInEditMode();
|
setCurrentTableCellInEditMode();
|
||||||
|
|
||||||
initFieldInputDraftValue(options?.initialValue);
|
initFieldInputDraftValue(options?.initialValue);
|
||||||
|
toggleClickOutsideListener(false);
|
||||||
|
|
||||||
if (isDefined(customCellHotkeyScope)) {
|
if (isDefined(customCellHotkeyScope)) {
|
||||||
setHotkeyScope(
|
setHotkeyScope(
|
||||||
@ -80,6 +86,7 @@ export const useOpenRecordTableCell = () => {
|
|||||||
setDragSelectionStartEnabled,
|
setDragSelectionStartEnabled,
|
||||||
setCurrentTableCellInEditMode,
|
setCurrentTableCellInEditMode,
|
||||||
initFieldInputDraftValue,
|
initFieldInputDraftValue,
|
||||||
|
toggleClickOutsideListener,
|
||||||
customCellHotkeyScope,
|
customCellHotkeyScope,
|
||||||
leaveTableFocus,
|
leaveTableFocus,
|
||||||
navigate,
|
navigate,
|
||||||
|
|||||||
@ -1,7 +1,5 @@
|
|||||||
import { RefObject, useEffect, useRef, useState } from 'react';
|
import { RefObject, useEffect, useRef, useState } from 'react';
|
||||||
import { useTheme } from '@emotion/react';
|
|
||||||
import styled from '@emotion/styled';
|
import styled from '@emotion/styled';
|
||||||
import { flip, offset, useFloating } from '@floating-ui/react';
|
|
||||||
import { Key } from 'ts-key-enum';
|
import { Key } from 'ts-key-enum';
|
||||||
|
|
||||||
import { FieldAddressDraftValue } from '@/object-record/record-field/types/FieldInputDraftValue';
|
import { FieldAddressDraftValue } from '@/object-record/record-field/types/FieldInputDraftValue';
|
||||||
@ -57,8 +55,6 @@ export const AddressInput = ({
|
|||||||
onClickOutside,
|
onClickOutside,
|
||||||
onChange,
|
onChange,
|
||||||
}: AddressInputProps) => {
|
}: AddressInputProps) => {
|
||||||
const theme = useTheme();
|
|
||||||
|
|
||||||
const [internalValue, setInternalValue] = useState(value);
|
const [internalValue, setInternalValue] = useState(value);
|
||||||
const addressStreet1InputRef = useRef<HTMLInputElement>(null);
|
const addressStreet1InputRef = useRef<HTMLInputElement>(null);
|
||||||
const addressStreet2InputRef = useRef<HTMLInputElement>(null);
|
const addressStreet2InputRef = useRef<HTMLInputElement>(null);
|
||||||
@ -81,16 +77,6 @@ export const AddressInput = ({
|
|||||||
|
|
||||||
const wrapperRef = useRef<HTMLDivElement>(null);
|
const wrapperRef = useRef<HTMLDivElement>(null);
|
||||||
|
|
||||||
const { refs, floatingStyles } = useFloating({
|
|
||||||
placement: 'top-start',
|
|
||||||
middleware: [
|
|
||||||
flip(),
|
|
||||||
offset({
|
|
||||||
mainAxis: theme.spacingMultiplicator * 2,
|
|
||||||
}),
|
|
||||||
],
|
|
||||||
});
|
|
||||||
|
|
||||||
const getChangeHandler =
|
const getChangeHandler =
|
||||||
(field: keyof FieldAddressDraftValue) => (updatedAddressPart: string) => {
|
(field: keyof FieldAddressDraftValue) => (updatedAddressPart: string) => {
|
||||||
const updatedAddress = { ...value, [field]: updatedAddressPart };
|
const updatedAddress = { ...value, [field]: updatedAddressPart };
|
||||||
@ -192,63 +178,61 @@ export const AddressInput = ({
|
|||||||
}, [value]);
|
}, [value]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div ref={refs.setFloating} style={floatingStyles}>
|
<StyledAddressContainer ref={wrapperRef}>
|
||||||
<StyledAddressContainer ref={wrapperRef}>
|
<TextInput
|
||||||
|
autoFocus
|
||||||
|
value={internalValue.addressStreet1 ?? ''}
|
||||||
|
ref={inputRefs['addressStreet1']}
|
||||||
|
label="ADDRESS 1"
|
||||||
|
fullWidth
|
||||||
|
onChange={getChangeHandler('addressStreet1')}
|
||||||
|
onFocus={getFocusHandler('addressStreet1')}
|
||||||
|
disableHotkeys
|
||||||
|
/>
|
||||||
|
<TextInput
|
||||||
|
value={internalValue.addressStreet2 ?? ''}
|
||||||
|
ref={inputRefs['addressStreet2']}
|
||||||
|
label="ADDRESS 2"
|
||||||
|
fullWidth
|
||||||
|
onChange={getChangeHandler('addressStreet2')}
|
||||||
|
onFocus={getFocusHandler('addressStreet2')}
|
||||||
|
disableHotkeys
|
||||||
|
/>
|
||||||
|
<StyledHalfRowContainer>
|
||||||
<TextInput
|
<TextInput
|
||||||
autoFocus
|
value={internalValue.addressCity ?? ''}
|
||||||
value={internalValue.addressStreet1 ?? ''}
|
ref={inputRefs['addressCity']}
|
||||||
ref={inputRefs['addressStreet1']}
|
label="CITY"
|
||||||
label="ADDRESS 1"
|
|
||||||
fullWidth
|
fullWidth
|
||||||
onChange={getChangeHandler('addressStreet1')}
|
onChange={getChangeHandler('addressCity')}
|
||||||
onFocus={getFocusHandler('addressStreet1')}
|
onFocus={getFocusHandler('addressCity')}
|
||||||
disableHotkeys
|
disableHotkeys
|
||||||
/>
|
/>
|
||||||
<TextInput
|
<TextInput
|
||||||
value={internalValue.addressStreet2 ?? ''}
|
value={internalValue.addressState ?? ''}
|
||||||
ref={inputRefs['addressStreet2']}
|
ref={inputRefs['addressState']}
|
||||||
label="ADDRESS 2"
|
label="STATE"
|
||||||
fullWidth
|
fullWidth
|
||||||
onChange={getChangeHandler('addressStreet2')}
|
onChange={getChangeHandler('addressState')}
|
||||||
onFocus={getFocusHandler('addressStreet2')}
|
onFocus={getFocusHandler('addressState')}
|
||||||
disableHotkeys
|
disableHotkeys
|
||||||
/>
|
/>
|
||||||
<StyledHalfRowContainer>
|
</StyledHalfRowContainer>
|
||||||
<TextInput
|
<StyledHalfRowContainer>
|
||||||
value={internalValue.addressCity ?? ''}
|
<TextInput
|
||||||
ref={inputRefs['addressCity']}
|
value={internalValue.addressPostcode ?? ''}
|
||||||
label="CITY"
|
ref={inputRefs['addressPostcode']}
|
||||||
fullWidth
|
label="POST CODE"
|
||||||
onChange={getChangeHandler('addressCity')}
|
fullWidth
|
||||||
onFocus={getFocusHandler('addressCity')}
|
onChange={getChangeHandler('addressPostcode')}
|
||||||
disableHotkeys
|
onFocus={getFocusHandler('addressPostcode')}
|
||||||
/>
|
disableHotkeys
|
||||||
<TextInput
|
/>
|
||||||
value={internalValue.addressState ?? ''}
|
<CountrySelect
|
||||||
ref={inputRefs['addressState']}
|
onChange={getChangeHandler('addressCountry')}
|
||||||
label="STATE"
|
selectedCountryName={internalValue.addressCountry ?? ''}
|
||||||
fullWidth
|
/>
|
||||||
onChange={getChangeHandler('addressState')}
|
</StyledHalfRowContainer>
|
||||||
onFocus={getFocusHandler('addressState')}
|
</StyledAddressContainer>
|
||||||
disableHotkeys
|
|
||||||
/>
|
|
||||||
</StyledHalfRowContainer>
|
|
||||||
<StyledHalfRowContainer>
|
|
||||||
<TextInput
|
|
||||||
value={internalValue.addressPostcode ?? ''}
|
|
||||||
ref={inputRefs['addressPostcode']}
|
|
||||||
label="POST CODE"
|
|
||||||
fullWidth
|
|
||||||
onChange={getChangeHandler('addressPostcode')}
|
|
||||||
onFocus={getFocusHandler('addressPostcode')}
|
|
||||||
disableHotkeys
|
|
||||||
/>
|
|
||||||
<CountrySelect
|
|
||||||
onChange={getChangeHandler('addressCountry')}
|
|
||||||
selectedCountryName={internalValue.addressCountry ?? ''}
|
|
||||||
/>
|
|
||||||
</StyledHalfRowContainer>
|
|
||||||
</StyledAddressContainer>
|
|
||||||
</div>
|
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@ -1,10 +1,7 @@
|
|||||||
import { useRef, useState } from 'react';
|
import { useRef, useState } from 'react';
|
||||||
import { useTheme } from '@emotion/react';
|
|
||||||
import styled from '@emotion/styled';
|
import styled from '@emotion/styled';
|
||||||
import { flip, offset, useFloating } from '@floating-ui/react';
|
|
||||||
import { Nullable } from 'twenty-ui';
|
import { Nullable } from 'twenty-ui';
|
||||||
|
|
||||||
import { DateDisplay } from '@/ui/field/display/components/DateDisplay';
|
|
||||||
import { InternalDatePicker } from '@/ui/input/components/internal/date/components/InternalDatePicker';
|
import { InternalDatePicker } from '@/ui/input/components/internal/date/components/InternalDatePicker';
|
||||||
import {
|
import {
|
||||||
MONTH_AND_YEAR_DROPDOWN_ID,
|
MONTH_AND_YEAR_DROPDOWN_ID,
|
||||||
@ -19,16 +16,9 @@ const StyledCalendarContainer = styled.div`
|
|||||||
border: 1px solid ${({ theme }) => theme.border.color.light};
|
border: 1px solid ${({ theme }) => theme.border.color.light};
|
||||||
border-radius: ${({ theme }) => theme.border.radius.md};
|
border-radius: ${({ theme }) => theme.border.radius.md};
|
||||||
box-shadow: ${({ theme }) => theme.boxShadow.strong};
|
box-shadow: ${({ theme }) => theme.boxShadow.strong};
|
||||||
|
top: 0;
|
||||||
|
|
||||||
position: absolute;
|
position: absolute;
|
||||||
|
|
||||||
z-index: 1;
|
|
||||||
`;
|
|
||||||
|
|
||||||
const StyledInputContainer = styled.div`
|
|
||||||
padding: ${({ theme }) => theme.spacing(0)} ${({ theme }) => theme.spacing(2)};
|
|
||||||
|
|
||||||
width: 100%;
|
|
||||||
`;
|
`;
|
||||||
|
|
||||||
export type DateInputProps = {
|
export type DateInputProps = {
|
||||||
@ -55,22 +45,10 @@ export const DateInput = ({
|
|||||||
isDateTimeInput,
|
isDateTimeInput,
|
||||||
onClear,
|
onClear,
|
||||||
}: DateInputProps) => {
|
}: DateInputProps) => {
|
||||||
const theme = useTheme();
|
|
||||||
|
|
||||||
const [internalValue, setInternalValue] = useState(value);
|
const [internalValue, setInternalValue] = useState(value);
|
||||||
|
|
||||||
const wrapperRef = useRef<HTMLDivElement>(null);
|
const wrapperRef = useRef<HTMLDivElement>(null);
|
||||||
|
|
||||||
const { refs, floatingStyles } = useFloating({
|
|
||||||
placement: 'bottom-start',
|
|
||||||
middleware: [
|
|
||||||
flip(),
|
|
||||||
offset({
|
|
||||||
mainAxis: theme.spacingMultiplicator * -6,
|
|
||||||
}),
|
|
||||||
],
|
|
||||||
});
|
|
||||||
|
|
||||||
const handleChange = (newDate: Date | null) => {
|
const handleChange = (newDate: Date | null) => {
|
||||||
setInternalValue(newDate);
|
setInternalValue(newDate);
|
||||||
onChange?.(newDate);
|
onChange?.(newDate);
|
||||||
@ -104,27 +82,20 @@ export const DateInput = ({
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<div ref={wrapperRef}>
|
<div ref={wrapperRef}>
|
||||||
<div ref={refs.setReference}>
|
<StyledCalendarContainer>
|
||||||
<StyledInputContainer>
|
<InternalDatePicker
|
||||||
<DateDisplay value={internalValue ?? new Date()} />
|
date={internalValue ?? new Date()}
|
||||||
</StyledInputContainer>
|
onChange={handleChange}
|
||||||
</div>
|
onMouseSelect={(newDate: Date | null) => {
|
||||||
<div ref={refs.setFloating} style={floatingStyles}>
|
onEnter(newDate);
|
||||||
<StyledCalendarContainer>
|
}}
|
||||||
<InternalDatePicker
|
clearable={clearable ? clearable : false}
|
||||||
date={internalValue ?? new Date()}
|
isDateTimeInput={isDateTimeInput}
|
||||||
onChange={handleChange}
|
onEnter={onEnter}
|
||||||
onMouseSelect={(newDate: Date | null) => {
|
onEscape={onEscape}
|
||||||
onEnter(newDate);
|
onClear={handleClear}
|
||||||
}}
|
/>
|
||||||
clearable={clearable ? clearable : false}
|
</StyledCalendarContainer>
|
||||||
isDateTimeInput={isDateTimeInput}
|
|
||||||
onEnter={onEnter}
|
|
||||||
onEscape={onEscape}
|
|
||||||
onClear={handleClear}
|
|
||||||
/>
|
|
||||||
</StyledCalendarContainer>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@ -20,7 +20,6 @@ const StyledInnerContainer = styled.div`
|
|||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
width: ${() => (useIsMobile() ? `100%` : '348px')};
|
width: ${() => (useIsMobile() ? `100%` : '348px')};
|
||||||
overflow-x: hidden;
|
|
||||||
`;
|
`;
|
||||||
|
|
||||||
const StyledIntermediateContainer = styled.div`
|
const StyledIntermediateContainer = styled.div`
|
||||||
|
|||||||
Reference in New Issue
Block a user