Files
twenty/packages/twenty-front/src/modules/ui/field/input/components/DateInput.tsx
T
Raphaël Bosi eba997be98 Replace hotkey scopes by focus stack (Part 6 - Remove Hotkey scopes 🫳🎤) (#13127)
# Replace hotkey scopes by focus stack (Part 6 - Remove Hotkey scopes)

This PR is the last part of a refactoring aiming to deprecate the hotkey
scopes api in favor of the new focus stack api which is more robust.
Part 1: https://github.com/twentyhq/twenty/pull/12673
Part 2: https://github.com/twentyhq/twenty/pull/12798
Part 3: https://github.com/twentyhq/twenty/pull/12910
Part 4: https://github.com/twentyhq/twenty/pull/12933
Part 5: https://github.com/twentyhq/twenty/pull/13106

In this part, we completely remove the hotkey scopes.
2025-07-09 17:21:14 +02:00

127 lines
3.4 KiB
TypeScript

import { useRef, useState } from 'react';
import { useRegisterInputEvents } from '@/object-record/record-field/meta-types/input/hooks/useRegisterInputEvents';
import {
DateTimePicker,
MONTH_AND_YEAR_DROPDOWN_MONTH_SELECT_ID,
MONTH_AND_YEAR_DROPDOWN_YEAR_SELECT_ID,
} from '@/ui/input/components/internal/date/components/InternalDatePicker';
import { useCloseDropdown } from '@/ui/layout/dropdown/hooks/useCloseDropdown';
import { currentFocusIdSelector } from '@/ui/utilities/focus/states/currentFocusIdSelector';
import { useRecoilCallback } from 'recoil';
import { Nullable } from 'twenty-ui/utilities';
export type DateInputProps = {
instanceId: string;
value: Nullable<Date>;
onEnter: (newDate: Nullable<Date>) => void;
onEscape: (newDate: Nullable<Date>) => void;
onClickOutside: (
event: MouseEvent | TouchEvent,
newDate: Nullable<Date>,
) => void;
clearable?: boolean;
onChange?: (newDate: Nullable<Date>) => void;
isDateTimeInput?: boolean;
onClear?: () => void;
onSubmit?: (newDate: Nullable<Date>) => void;
hideHeaderInput?: boolean;
};
export const DateInput = ({
instanceId,
value,
onEnter,
onEscape,
onClickOutside,
clearable,
onChange,
isDateTimeInput,
onClear,
onSubmit,
hideHeaderInput,
}: DateInputProps) => {
const [internalValue, setInternalValue] = useState(value);
const wrapperRef = useRef<HTMLDivElement>(null);
const handleChange = (newDate: Date | null) => {
setInternalValue(newDate);
onChange?.(newDate);
};
const handleClear = () => {
setInternalValue(null);
onClear?.();
};
const handleClose = (newDate: Date | null) => {
setInternalValue(newDate);
onSubmit?.(newDate);
};
const { closeDropdown: closeDropdownMonthSelect } = useCloseDropdown();
const { closeDropdown: closeDropdownYearSelect } = useCloseDropdown();
const handleEnter = () => {
closeDropdownYearSelect(MONTH_AND_YEAR_DROPDOWN_YEAR_SELECT_ID);
closeDropdownMonthSelect(MONTH_AND_YEAR_DROPDOWN_MONTH_SELECT_ID);
onEnter(internalValue);
};
const handleEscape = () => {
closeDropdownYearSelect(MONTH_AND_YEAR_DROPDOWN_YEAR_SELECT_ID);
closeDropdownMonthSelect(MONTH_AND_YEAR_DROPDOWN_MONTH_SELECT_ID);
onEscape(internalValue);
};
const handleClickOutside = useRecoilCallback(
({ snapshot }) =>
(event: MouseEvent | TouchEvent) => {
const currentFocusId = snapshot
.getLoadable(currentFocusIdSelector)
.getValue();
if (currentFocusId === instanceId) {
closeDropdownYearSelect(MONTH_AND_YEAR_DROPDOWN_YEAR_SELECT_ID);
closeDropdownMonthSelect(MONTH_AND_YEAR_DROPDOWN_MONTH_SELECT_ID);
onClickOutside(event, internalValue);
}
},
[
instanceId,
closeDropdownYearSelect,
closeDropdownMonthSelect,
onClickOutside,
internalValue,
],
);
useRegisterInputEvents({
focusId: instanceId,
inputRef: wrapperRef,
inputValue: internalValue,
onEnter: handleEnter,
onEscape: handleEscape,
onClickOutside: handleClickOutside,
});
return (
<div ref={wrapperRef}>
<DateTimePicker
date={internalValue ?? null}
onChange={handleChange}
onClose={handleClose}
clearable={clearable ?? false}
onEnter={onEnter}
onEscape={onEscape}
onClear={handleClear}
hideHeaderInput={hideHeaderInput}
isDateTimeInput={isDateTimeInput}
/>
</div>
);
};