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
@@ -2,14 +2,17 @@ import styled from '@emotion/styled';
import { FocusEventHandler, useId } from 'react';
import TextareaAutosize from 'react-textarea-autosize';
import { usePreviousHotkeyScope } from '@/ui/utilities/hotkey/hooks/usePreviousHotkeyScope';
import { InputHotkeyScope } from '@/ui/input/types/InputHotkeyScope';
import { usePushFocusItemToFocusStack } from '@/ui/utilities/focus/hooks/usePushFocusItemToFocusStack';
import { useRemoveFocusItemFromFocusStackById } from '@/ui/utilities/focus/hooks/useRemoveFocusItemFromFocusStackById';
import { FocusComponentType } from '@/ui/utilities/focus/types/FocusComponentType';
import { RGBA } from 'twenty-ui/theme';
import { turnIntoEmptyStringIfWhitespacesOnly } from '~/utils/string/turnIntoEmptyStringIfWhitespacesOnly';
import { InputHotkeyScope } from '../types/InputHotkeyScope';
const MAX_ROWS = 5;
export type TextAreaProps = {
textAreaId: string;
label?: string;
disabled?: boolean;
minRows?: number;
@@ -69,6 +72,7 @@ const StyledTextArea = styled(TextareaAutosize)`
`;
export const TextArea = ({
textAreaId,
label,
disabled,
placeholder,
@@ -81,30 +85,37 @@ export const TextArea = ({
}: TextAreaProps) => {
const computedMinRows = Math.min(minRows, maxRows);
const inputId = useId();
const instanceId = useId();
const {
goBackToPreviousHotkeyScope,
setHotkeyScopeAndMemorizePreviousScope,
} = usePreviousHotkeyScope();
const { pushFocusItemToFocusStack } = usePushFocusItemToFocusStack();
const { removeFocusItemFromFocusStackById } =
useRemoveFocusItemFromFocusStackById();
const handleFocus: FocusEventHandler<HTMLTextAreaElement> = () => {
setHotkeyScopeAndMemorizePreviousScope({
scope: InputHotkeyScope.TextInput,
pushFocusItemToFocusStack({
focusId: textAreaId,
component: {
type: FocusComponentType.TEXT_AREA,
instanceId: textAreaId,
},
globalHotkeysConfig: {
enableGlobalHotkeysConflictingWithKeyboard: false,
},
hotkeyScope: { scope: InputHotkeyScope.TextInput },
});
};
const handleBlur: FocusEventHandler<HTMLTextAreaElement> = () => {
goBackToPreviousHotkeyScope();
removeFocusItemFromFocusStackById({ focusId: textAreaId });
onBlur?.();
};
return (
<StyledContainer>
{label && <StyledLabel htmlFor={inputId}>{label}</StyledLabel>}
{label && <StyledLabel htmlFor={instanceId}>{label}</StyledLabel>}
<StyledTextArea
id={inputId}
id={instanceId}
placeholder={placeholder}
maxRows={maxRows}
minRows={computedMinRows}