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,5 @@
|
||||
import { RefObject, useEffect, useRef, useState } from 'react';
|
||||
import { useTheme } from '@emotion/react';
|
||||
import styled from '@emotion/styled';
|
||||
import { flip, offset, useFloating } from '@floating-ui/react';
|
||||
import { Key } from 'ts-key-enum';
|
||||
|
||||
import { FieldAddressDraftValue } from '@/object-record/record-field/types/FieldInputDraftValue';
|
||||
@ -57,8 +55,6 @@ export const AddressInput = ({
|
||||
onClickOutside,
|
||||
onChange,
|
||||
}: AddressInputProps) => {
|
||||
const theme = useTheme();
|
||||
|
||||
const [internalValue, setInternalValue] = useState(value);
|
||||
const addressStreet1InputRef = useRef<HTMLInputElement>(null);
|
||||
const addressStreet2InputRef = useRef<HTMLInputElement>(null);
|
||||
@ -81,16 +77,6 @@ export const AddressInput = ({
|
||||
|
||||
const wrapperRef = useRef<HTMLDivElement>(null);
|
||||
|
||||
const { refs, floatingStyles } = useFloating({
|
||||
placement: 'top-start',
|
||||
middleware: [
|
||||
flip(),
|
||||
offset({
|
||||
mainAxis: theme.spacingMultiplicator * 2,
|
||||
}),
|
||||
],
|
||||
});
|
||||
|
||||
const getChangeHandler =
|
||||
(field: keyof FieldAddressDraftValue) => (updatedAddressPart: string) => {
|
||||
const updatedAddress = { ...value, [field]: updatedAddressPart };
|
||||
@ -192,63 +178,61 @@ export const AddressInput = ({
|
||||
}, [value]);
|
||||
|
||||
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
|
||||
autoFocus
|
||||
value={internalValue.addressStreet1 ?? ''}
|
||||
ref={inputRefs['addressStreet1']}
|
||||
label="ADDRESS 1"
|
||||
value={internalValue.addressCity ?? ''}
|
||||
ref={inputRefs['addressCity']}
|
||||
label="CITY"
|
||||
fullWidth
|
||||
onChange={getChangeHandler('addressStreet1')}
|
||||
onFocus={getFocusHandler('addressStreet1')}
|
||||
onChange={getChangeHandler('addressCity')}
|
||||
onFocus={getFocusHandler('addressCity')}
|
||||
disableHotkeys
|
||||
/>
|
||||
<TextInput
|
||||
value={internalValue.addressStreet2 ?? ''}
|
||||
ref={inputRefs['addressStreet2']}
|
||||
label="ADDRESS 2"
|
||||
value={internalValue.addressState ?? ''}
|
||||
ref={inputRefs['addressState']}
|
||||
label="STATE"
|
||||
fullWidth
|
||||
onChange={getChangeHandler('addressStreet2')}
|
||||
onFocus={getFocusHandler('addressStreet2')}
|
||||
onChange={getChangeHandler('addressState')}
|
||||
onFocus={getFocusHandler('addressState')}
|
||||
disableHotkeys
|
||||
/>
|
||||
<StyledHalfRowContainer>
|
||||
<TextInput
|
||||
value={internalValue.addressCity ?? ''}
|
||||
ref={inputRefs['addressCity']}
|
||||
label="CITY"
|
||||
fullWidth
|
||||
onChange={getChangeHandler('addressCity')}
|
||||
onFocus={getFocusHandler('addressCity')}
|
||||
disableHotkeys
|
||||
/>
|
||||
<TextInput
|
||||
value={internalValue.addressState ?? ''}
|
||||
ref={inputRefs['addressState']}
|
||||
label="STATE"
|
||||
fullWidth
|
||||
onChange={getChangeHandler('addressState')}
|
||||
onFocus={getFocusHandler('addressState')}
|
||||
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>
|
||||
</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>
|
||||
);
|
||||
};
|
||||
|
||||
@ -1,10 +1,7 @@
|
||||
import { useRef, useState } from 'react';
|
||||
import { useTheme } from '@emotion/react';
|
||||
import styled from '@emotion/styled';
|
||||
import { flip, offset, useFloating } from '@floating-ui/react';
|
||||
import { Nullable } from 'twenty-ui';
|
||||
|
||||
import { DateDisplay } from '@/ui/field/display/components/DateDisplay';
|
||||
import { InternalDatePicker } from '@/ui/input/components/internal/date/components/InternalDatePicker';
|
||||
import {
|
||||
MONTH_AND_YEAR_DROPDOWN_ID,
|
||||
@ -19,16 +16,9 @@ const StyledCalendarContainer = styled.div`
|
||||
border: 1px solid ${({ theme }) => theme.border.color.light};
|
||||
border-radius: ${({ theme }) => theme.border.radius.md};
|
||||
box-shadow: ${({ theme }) => theme.boxShadow.strong};
|
||||
top: 0;
|
||||
|
||||
position: absolute;
|
||||
|
||||
z-index: 1;
|
||||
`;
|
||||
|
||||
const StyledInputContainer = styled.div`
|
||||
padding: ${({ theme }) => theme.spacing(0)} ${({ theme }) => theme.spacing(2)};
|
||||
|
||||
width: 100%;
|
||||
`;
|
||||
|
||||
export type DateInputProps = {
|
||||
@ -55,22 +45,10 @@ export const DateInput = ({
|
||||
isDateTimeInput,
|
||||
onClear,
|
||||
}: DateInputProps) => {
|
||||
const theme = useTheme();
|
||||
|
||||
const [internalValue, setInternalValue] = useState(value);
|
||||
|
||||
const wrapperRef = useRef<HTMLDivElement>(null);
|
||||
|
||||
const { refs, floatingStyles } = useFloating({
|
||||
placement: 'bottom-start',
|
||||
middleware: [
|
||||
flip(),
|
||||
offset({
|
||||
mainAxis: theme.spacingMultiplicator * -6,
|
||||
}),
|
||||
],
|
||||
});
|
||||
|
||||
const handleChange = (newDate: Date | null) => {
|
||||
setInternalValue(newDate);
|
||||
onChange?.(newDate);
|
||||
@ -104,27 +82,20 @@ export const DateInput = ({
|
||||
|
||||
return (
|
||||
<div ref={wrapperRef}>
|
||||
<div ref={refs.setReference}>
|
||||
<StyledInputContainer>
|
||||
<DateDisplay value={internalValue ?? new Date()} />
|
||||
</StyledInputContainer>
|
||||
</div>
|
||||
<div ref={refs.setFloating} style={floatingStyles}>
|
||||
<StyledCalendarContainer>
|
||||
<InternalDatePicker
|
||||
date={internalValue ?? new Date()}
|
||||
onChange={handleChange}
|
||||
onMouseSelect={(newDate: Date | null) => {
|
||||
onEnter(newDate);
|
||||
}}
|
||||
clearable={clearable ? clearable : false}
|
||||
isDateTimeInput={isDateTimeInput}
|
||||
onEnter={onEnter}
|
||||
onEscape={onEscape}
|
||||
onClear={handleClear}
|
||||
/>
|
||||
</StyledCalendarContainer>
|
||||
</div>
|
||||
<StyledCalendarContainer>
|
||||
<InternalDatePicker
|
||||
date={internalValue ?? new Date()}
|
||||
onChange={handleChange}
|
||||
onMouseSelect={(newDate: Date | null) => {
|
||||
onEnter(newDate);
|
||||
}}
|
||||
clearable={clearable ? clearable : false}
|
||||
isDateTimeInput={isDateTimeInput}
|
||||
onEnter={onEnter}
|
||||
onEscape={onEscape}
|
||||
onClear={handleClear}
|
||||
/>
|
||||
</StyledCalendarContainer>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
@ -20,7 +20,6 @@ const StyledInnerContainer = styled.div`
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
width: ${() => (useIsMobile() ? `100%` : '348px')};
|
||||
overflow-x: hidden;
|
||||
`;
|
||||
|
||||
const StyledIntermediateContainer = styled.div`
|
||||
|
||||
Reference in New Issue
Block a user