Fixed date input fields (#9442)

- Fixed date input fields : proper hotkey management, like other fields
- Removed DropdownUnmountEffect which was causing many bugs.
This commit is contained in:
Lucas Bordeau
2025-01-08 10:43:49 +01:00
committed by GitHub
parent 3198748401
commit 00a9646d68
7 changed files with 44 additions and 63 deletions

View File

@ -1,6 +1,10 @@
import { usePreviousHotkeyScope } from '@/ui/utilities/hotkey/hooks/usePreviousHotkeyScope'; import { usePreviousHotkeyScope } from '@/ui/utilities/hotkey/hooks/usePreviousHotkeyScope';
import { useEffect } from 'react'; import { useEffect } from 'react';
/**
* @deprecated This hook uses useEffect
* Use event handlers and imperative code to manage hotkey scope changes.
*/
export const useHotkeyScopeOnMount = (hotkeyScope: string) => { export const useHotkeyScopeOnMount = (hotkeyScope: string) => {
const { const {
goBackToPreviousHotkeyScope, goBackToPreviousHotkeyScope,

View File

@ -24,7 +24,7 @@ export const DateFieldInput = ({
onClear, onClear,
onSubmit, onSubmit,
}: DateFieldInputProps) => { }: DateFieldInputProps) => {
const { fieldValue, setDraftValue } = useDateField(); const { fieldValue, setDraftValue, hotkeyScope } = useDateField();
const persistField = usePersistField(); const persistField = usePersistField();
@ -77,6 +77,7 @@ export const DateFieldInput = ({
onChange={handleChange} onChange={handleChange}
onClear={handleClear} onClear={handleClear}
onSubmit={handleSubmit} onSubmit={handleSubmit}
hotkeyScope={hotkeyScope}
/> />
); );
}; };

View File

@ -26,7 +26,7 @@ export const DateTimeFieldInput = ({
onClear, onClear,
onSubmit, onSubmit,
}: DateTimeFieldInputProps) => { }: DateTimeFieldInputProps) => {
const { fieldValue, setDraftValue } = useDateTimeField(); const { fieldValue, setDraftValue, hotkeyScope } = useDateTimeField();
const persistField = usePersistField(); const persistField = usePersistField();
@ -80,6 +80,7 @@ export const DateTimeFieldInput = ({
isDateTimeInput isDateTimeInput
onClear={handleClear} onClear={handleClear}
onSubmit={handleSubmit} onSubmit={handleSubmit}
hotkeyScope={hotkeyScope}
/> />
); );
}; };

View File

@ -1,6 +1,7 @@
import { useRef, useState } from 'react'; import { useRef, useState } from 'react';
import { Nullable } from 'twenty-ui'; import { Nullable } from 'twenty-ui';
import { useRegisterInputEvents } from '@/object-record/record-field/meta-types/input/hooks/useRegisterInputEvents';
import { import {
InternalDatePicker, InternalDatePicker,
MONTH_AND_YEAR_DROPDOWN_ID, MONTH_AND_YEAR_DROPDOWN_ID,
@ -8,7 +9,6 @@ import {
MONTH_AND_YEAR_DROPDOWN_YEAR_SELECT_ID, MONTH_AND_YEAR_DROPDOWN_YEAR_SELECT_ID,
} from '@/ui/input/components/internal/date/components/InternalDatePicker'; } from '@/ui/input/components/internal/date/components/InternalDatePicker';
import { useDropdown } from '@/ui/layout/dropdown/hooks/useDropdown'; import { useDropdown } from '@/ui/layout/dropdown/hooks/useDropdown';
import { useListenClickOutside } from '@/ui/utilities/pointer-event/hooks/useListenClickOutside';
export type DateInputProps = { export type DateInputProps = {
value: Nullable<Date>; value: Nullable<Date>;
@ -24,6 +24,7 @@ export type DateInputProps = {
onClear?: () => void; onClear?: () => void;
onSubmit?: (newDate: Nullable<Date>) => void; onSubmit?: (newDate: Nullable<Date>) => void;
hideHeaderInput?: boolean; hideHeaderInput?: boolean;
hotkeyScope: string;
}; };
export const DateInput = ({ export const DateInput = ({
@ -37,6 +38,7 @@ export const DateInput = ({
onClear, onClear,
onSubmit, onSubmit,
hideHeaderInput, hideHeaderInput,
hotkeyScope,
}: DateInputProps) => { }: DateInputProps) => {
const [internalValue, setInternalValue] = useState(value); const [internalValue, setInternalValue] = useState(value);
@ -65,17 +67,39 @@ export const DateInput = ({
MONTH_AND_YEAR_DROPDOWN_YEAR_SELECT_ID, MONTH_AND_YEAR_DROPDOWN_YEAR_SELECT_ID,
); );
useListenClickOutside({ const handleEnter = () => {
refs: [wrapperRef], closeDropdownYearSelect();
listenerId: 'DateInput', closeDropdownMonthSelect();
callback: (event) => { closeDropdown();
event.stopImmediatePropagation();
closeDropdownYearSelect(); onEnter?.(internalValue);
closeDropdownMonthSelect(); };
closeDropdown();
onClickOutside(event, internalValue); const handleEscape = () => {
}, closeDropdownYearSelect();
closeDropdownMonthSelect();
closeDropdown();
onEscape?.(internalValue);
};
const handleClickOutside = (event: MouseEvent | TouchEvent) => {
event.stopImmediatePropagation();
closeDropdownYearSelect();
closeDropdownMonthSelect();
closeDropdown();
onClickOutside(event, internalValue);
};
useRegisterInputEvents({
inputRef: wrapperRef,
inputValue: internalValue,
onEnter: handleEnter,
onEscape: handleEscape,
onClickOutside: handleClickOutside,
hotkeyScope: hotkeyScope,
}); });
return ( return (

View File

@ -1,7 +1,6 @@
import styled from '@emotion/styled'; import styled from '@emotion/styled';
import { DateTime } from 'luxon'; import { DateTime } from 'luxon';
import ReactDatePicker from 'react-datepicker'; import ReactDatePicker from 'react-datepicker';
import { Key } from 'ts-key-enum';
import { import {
IconCalendarX, IconCalendarX,
MenuItemLeftContent, MenuItemLeftContent,
@ -305,11 +304,8 @@ export const InternalDatePicker = ({
date, date,
onChange, onChange,
onMouseSelect, onMouseSelect,
onEnter,
onEscape,
clearable = true, clearable = true,
isDateTimeInput, isDateTimeInput,
keyboardEventsDisabled,
onClear, onClear,
isRelative, isRelative,
relativeDate, relativeDate,
@ -345,31 +341,6 @@ export const InternalDatePicker = ({
onMouseSelect?.(newDate); onMouseSelect?.(newDate);
}; };
const handleKeyDown = (event: React.KeyboardEvent<HTMLDivElement>) => {
if (isDefined(keyboardEventsDisabled) && keyboardEventsDisabled) {
return;
}
switch (event.key) {
case Key.Enter: {
event.stopPropagation();
event.preventDefault();
closeDropdowns();
onEnter?.(internalDate);
break;
}
case Key.Escape: {
event.stopPropagation();
event.preventDefault();
closeDropdowns();
onEscape?.(internalDate);
break;
}
}
};
const handleChangeMonth = (month: number) => { const handleChangeMonth = (month: number) => {
const newDate = new Date(internalDate); const newDate = new Date(internalDate);
newDate.setMonth(month); newDate.setMonth(month);
@ -469,7 +440,7 @@ export const InternalDatePicker = ({
const selectedDates = isRelative ? highlightedDates : [dateToUse]; const selectedDates = isRelative ? highlightedDates : [dateToUse];
return ( return (
<StyledContainer onKeyDown={handleKeyDown} calendarDisabled={isRelative}> <StyledContainer calendarDisabled={isRelative}>
<div className={clearable ? 'clearable ' : ''}> <div className={clearable ? 'clearable ' : ''}>
<ReactDatePicker <ReactDatePicker
open={true} open={true}

View File

@ -15,7 +15,6 @@ import { Keys } from 'react-hotkeys-hook';
import { useDropdown } from '../hooks/useDropdown'; import { useDropdown } from '../hooks/useDropdown';
import { DropdownContent } from '@/ui/layout/dropdown/components/DropdownContent'; import { DropdownContent } from '@/ui/layout/dropdown/components/DropdownContent';
import { DropdownUnmountEffect } from '@/ui/layout/dropdown/components/DropdownUnmountEffect';
import { DropdownComponentInstanceContext } from '@/ui/layout/dropdown/contexts/DropdownComponeInstanceContext'; import { DropdownComponentInstanceContext } from '@/ui/layout/dropdown/contexts/DropdownComponeInstanceContext';
import { dropdownHotkeyComponentState } from '@/ui/layout/dropdown/states/dropdownHotkeyComponentState'; import { dropdownHotkeyComponentState } from '@/ui/layout/dropdown/states/dropdownHotkeyComponentState';
import { dropdownMaxHeightComponentStateV2 } from '@/ui/layout/dropdown/states/dropdownMaxHeightComponentStateV2'; import { dropdownMaxHeightComponentStateV2 } from '@/ui/layout/dropdown/states/dropdownMaxHeightComponentStateV2';
@ -165,7 +164,6 @@ export const Dropdown = ({
/> />
</> </>
</DropdownScope> </DropdownScope>
<DropdownUnmountEffect dropdownId={dropdownId} />
</DropdownComponentInstanceContext.Provider> </DropdownComponentInstanceContext.Provider>
); );
}; };

View File

@ -1,18 +0,0 @@
import { useDropdownV2 } from '@/ui/layout/dropdown/hooks/useDropdownV2';
import { useEffect } from 'react';
export const DropdownUnmountEffect = ({
dropdownId,
}: {
dropdownId: string;
}) => {
const { closeDropdown } = useDropdownV2();
useEffect(() => {
return () => {
closeDropdown(dropdownId);
};
}, [closeDropdown, dropdownId]);
return null;
};