Files
twenty_crm/packages/twenty-front/src/modules/ui/input/components/TextInput.tsx
Ngan Phan 2bc7974da9 fix: Improve Usability of Adding Options via Return Key for Multi-Select Field (#7450)
Fixes #6602

This is the approach that I followed based on these comments
https://github.com/twentyhq/twenty/issues/6602#issuecomment-2356870311,
https://github.com/twentyhq/twenty/issues/6602#issuecomment-2330737907
- Create forward ref in `<TextInput>` component
- Create ref to select text in parent component
`<SettingsDataModelFieldSelectFormOptionRow>` and pass it to
`<TextInput>`

---------

Co-authored-by: Lucas Bordeau <bordeau.lucas@gmail.com>
2024-10-07 13:06:51 +02:00

121 lines
2.6 KiB
TypeScript

import { FocusEventHandler, useEffect, useRef, useState } from 'react';
import { Key } from 'ts-key-enum';
import {
TextInputV2,
TextInputV2ComponentProps,
} from '@/ui/input/components/TextInputV2';
import { InputHotkeyScope } from '@/ui/input/types/InputHotkeyScope';
import { usePreviousHotkeyScope } from '@/ui/utilities/hotkey/hooks/usePreviousHotkeyScope';
import { useScopedHotkeys } from '@/ui/utilities/hotkey/hooks/useScopedHotkeys';
import { isDefined } from '~/utils/isDefined';
export type TextInputProps = TextInputV2ComponentProps & {
disableHotkeys?: boolean;
onInputEnter?: () => void;
dataTestId?: string;
autoFocusOnMount?: boolean;
autoSelectOnMount?: boolean;
};
export const TextInput = ({
onFocus,
onBlur,
onInputEnter,
disableHotkeys = false,
autoFocusOnMount,
autoSelectOnMount,
dataTestId,
...props
}: TextInputProps) => {
const inputRef = useRef<HTMLInputElement>(null);
const [isFocused, setIsFocused] = useState(false);
useEffect(() => {
if (autoFocusOnMount === true) {
inputRef.current?.focus();
setIsFocused(true);
}
}, [autoFocusOnMount]);
useEffect(() => {
if (autoSelectOnMount === true) {
inputRef.current?.select();
}
}, [autoSelectOnMount]);
const {
goBackToPreviousHotkeyScope,
setHotkeyScopeAndMemorizePreviousScope,
} = usePreviousHotkeyScope();
const handleFocus: FocusEventHandler<HTMLInputElement> = (e) => {
onFocus?.(e);
setIsFocused(true);
if (!disableHotkeys) {
setHotkeyScopeAndMemorizePreviousScope(InputHotkeyScope.TextInput);
}
};
const handleBlur: FocusEventHandler<HTMLInputElement> = (e) => {
onBlur?.(e);
setIsFocused(false);
if (!disableHotkeys) {
goBackToPreviousHotkeyScope();
}
};
useScopedHotkeys(
[Key.Escape],
() => {
if (!isFocused) {
return;
}
if (isDefined(inputRef) && 'current' in inputRef) {
inputRef.current?.blur();
setIsFocused(false);
}
},
InputHotkeyScope.TextInput,
[inputRef, isFocused],
{
preventDefault: false,
},
);
useScopedHotkeys(
[Key.Enter],
() => {
if (!isFocused) {
return;
}
onInputEnter?.();
if (isDefined(inputRef) && 'current' in inputRef) {
setIsFocused(false);
}
},
InputHotkeyScope.TextInput,
[inputRef, isFocused, onInputEnter],
{
preventDefault: false,
},
);
return (
<TextInputV2
ref={inputRef}
// eslint-disable-next-line react/jsx-props-no-spreading
{...props}
dataTestId={dataTestId}
onFocus={handleFocus}
onBlur={handleBlur}
/>
);
};