Replace hotkey scopes by focus stack (Part 4 - Inputs) (#12933)

# Replace hotkey scopes by focus stack (Part 4 - Inputs)

This PR is the 4th 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

In this part, I refactored all inputs in the app so that each input has
a unique id which can be used to track the focused element.
This commit is contained in:
Raphaël Bosi
2025-07-07 15:42:12 +02:00
committed by GitHub
parent 0199d5f72a
commit c6e5bab4e9
140 changed files with 1178 additions and 1004 deletions
@@ -9,14 +9,14 @@ import {
import { Key } from 'ts-key-enum';
import { FieldDoubleText } from '@/object-record/record-field/types/FieldDoubleText';
import { useScopedHotkeys } from '@/ui/utilities/hotkey/hooks/useScopedHotkeys';
import { FieldInputContainer } from '@/ui/field/input/components/FieldInputContainer';
import { useHotkeysOnFocusedElement } from '@/ui/utilities/hotkey/hooks/useHotkeysOnFocusedElement';
import { useListenClickOutside } from '@/ui/utilities/pointer-event/hooks/useListenClickOutside';
import { isDefined } from 'twenty-shared/utils';
import { splitFullName } from '~/utils/format/spiltFullName';
import { turnIntoEmptyStringIfWhitespacesOnly } from '~/utils/string/turnIntoEmptyStringIfWhitespacesOnly';
import { StyledTextInput } from './TextInput';
import { isDefined } from 'twenty-shared/utils';
const StyledContainer = styled.div`
display: flex;
@@ -29,6 +29,7 @@ const StyledContainer = styled.div`
`;
type DoubleTextInputProps = {
instanceId: string;
firstValue: string;
secondValue: string;
firstValuePlaceholder: string;
@@ -47,6 +48,7 @@ type DoubleTextInputProps = {
};
export const DoubleTextInput = ({
instanceId,
firstValue,
secondValue,
firstValuePlaceholder,
@@ -87,33 +89,35 @@ export const DoubleTextInput = ({
const [focusPosition, setFocusPosition] = useState<'left' | 'right'>('left');
useScopedHotkeys(
Key.Enter,
() => {
useHotkeysOnFocusedElement({
keys: [Key.Enter],
callback: () => {
onEnter({
firstValue: firstInternalValue,
secondValue: secondInternalValue,
});
},
hotkeyScope,
[onEnter, firstInternalValue, secondInternalValue],
);
scope: hotkeyScope,
focusId: instanceId,
dependencies: [onEnter, firstInternalValue, secondInternalValue],
});
useScopedHotkeys(
[Key.Escape],
() => {
useHotkeysOnFocusedElement({
keys: [Key.Escape],
callback: () => {
onEscape({
firstValue: firstInternalValue,
secondValue: secondInternalValue,
});
},
hotkeyScope,
[onEscape, firstInternalValue, secondInternalValue],
);
scope: hotkeyScope,
focusId: instanceId,
dependencies: [onEscape, firstInternalValue, secondInternalValue],
});
useScopedHotkeys(
'tab',
() => {
useHotkeysOnFocusedElement({
keys: ['tab'],
callback: () => {
if (focusPosition === 'left') {
setFocusPosition('right');
secondValueInputRef.current?.focus();
@@ -124,13 +128,19 @@ export const DoubleTextInput = ({
});
}
},
hotkeyScope,
[onTab, firstInternalValue, secondInternalValue, focusPosition],
);
scope: hotkeyScope,
focusId: instanceId,
dependencies: [
onTab,
firstInternalValue,
secondInternalValue,
focusPosition,
],
});
useScopedHotkeys(
'shift+tab',
() => {
useHotkeysOnFocusedElement({
keys: ['shift+tab'],
callback: () => {
if (focusPosition === 'right') {
setFocusPosition('left');
firstValueInputRef.current?.focus();
@@ -141,9 +151,15 @@ export const DoubleTextInput = ({
});
}
},
hotkeyScope,
[onShiftTab, firstInternalValue, secondInternalValue, focusPosition],
);
scope: hotkeyScope,
focusId: instanceId,
dependencies: [
onShiftTab,
firstInternalValue,
secondInternalValue,
focusPosition,
],
});
useListenClickOutside({
refs: [containerRef],