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>
This commit is contained in:
Ngan Phan
2024-10-07 04:06:51 -07:00
committed by GitHub
parent db9ec58f5d
commit 2bc7974da9
4 changed files with 23 additions and 20 deletions

View File

@@ -1,6 +1,5 @@
import styled from '@emotion/styled'; import styled from '@emotion/styled';
import { DropResult } from '@hello-pangea/dnd'; import { DropResult } from '@hello-pangea/dnd';
import { useState } from 'react';
import { Controller, useFormContext } from 'react-hook-form'; import { Controller, useFormContext } from 'react-hook-form';
import { IconPlus } from 'twenty-ui'; import { IconPlus } from 'twenty-ui';
import { z } from 'zod'; import { z } from 'zod';
@@ -79,7 +78,6 @@ const StyledButton = styled(LightButton)`
export const SettingsDataModelFieldSelectForm = ({ export const SettingsDataModelFieldSelectForm = ({
fieldMetadataItem, fieldMetadataItem,
}: SettingsDataModelFieldSelectFormProps) => { }: SettingsDataModelFieldSelectFormProps) => {
const [focusedOptionId, setFocusedOptionId] = useState('');
const { initialDefaultValue, initialOptions } = const { initialDefaultValue, initialOptions } =
useSelectSettingsFormInitialValues({ fieldMetadataItem }); useSelectSettingsFormInitialValues({ fieldMetadataItem });
@@ -190,10 +188,6 @@ export const SettingsDataModelFieldSelectForm = ({
const newOptions = getOptionsWithNewOption(); const newOptions = getOptionsWithNewOption();
setFormValue('options', newOptions); setFormValue('options', newOptions);
const lastOptionId = newOptions[newOptions.length - 1].id;
setFocusedOptionId(lastOptionId);
}; };
return ( return (
@@ -227,7 +221,7 @@ export const SettingsDataModelFieldSelectForm = ({
<SettingsDataModelFieldSelectFormOptionRow <SettingsDataModelFieldSelectFormOptionRow
key={option.id} key={option.id}
option={option} option={option}
focused={focusedOptionId === option.id} isNewRow={index === options.length - 1}
onChange={(nextOption) => { onChange={(nextOption) => {
const nextOptions = toSpliced( const nextOptions = toSpliced(
options, options,

View File

@@ -33,7 +33,7 @@ type SettingsDataModelFieldSelectFormOptionRowProps = {
onRemoveAsDefault?: () => void; onRemoveAsDefault?: () => void;
onInputEnter?: () => void; onInputEnter?: () => void;
option: FieldMetadataItemOption; option: FieldMetadataItemOption;
focused?: boolean; isNewRow?: boolean;
}; };
const StyledRow = styled.div` const StyledRow = styled.div`
@@ -67,7 +67,7 @@ export const SettingsDataModelFieldSelectFormOptionRow = ({
onRemoveAsDefault, onRemoveAsDefault,
onInputEnter, onInputEnter,
option, option,
focused, isNewRow,
}: SettingsDataModelFieldSelectFormOptionRowProps) => { }: SettingsDataModelFieldSelectFormOptionRowProps) => {
const theme = useTheme(); const theme = useTheme();
@@ -129,10 +129,11 @@ export const SettingsDataModelFieldSelectFormOptionRow = ({
value: getOptionValueFromLabel(label), value: getOptionValueFromLabel(label),
}) })
} }
focused={focused}
RightIcon={isDefault ? IconCheck : undefined} RightIcon={isDefault ? IconCheck : undefined}
maxLength={OPTION_VALUE_MAXIMUM_LENGTH} maxLength={OPTION_VALUE_MAXIMUM_LENGTH}
onInputEnter={handleInputEnter} onInputEnter={handleInputEnter}
autoFocusOnMount={isNewRow}
autoSelectOnMount={isNewRow}
/> />
<Dropdown <Dropdown
dropdownId={dropdownIds.actions} dropdownId={dropdownIds.actions}

View File

@@ -1,9 +1,9 @@
import { H2Title } from 'twenty-ui';
import { Section } from '@/ui/layout/section/components/Section';
import { TextInput } from '@/ui/input/components/TextInput';
import { TextArea } from '@/ui/input/components/TextArea';
import styled from '@emotion/styled';
import { ServerlessFunctionNewFormValues } from '@/settings/serverless-functions/hooks/useServerlessFunctionUpdateFormState'; import { ServerlessFunctionNewFormValues } from '@/settings/serverless-functions/hooks/useServerlessFunctionUpdateFormState';
import { TextArea } from '@/ui/input/components/TextArea';
import { TextInput } from '@/ui/input/components/TextInput';
import { Section } from '@/ui/layout/section/components/Section';
import styled from '@emotion/styled';
import { H2Title } from 'twenty-ui';
const StyledInputsContainer = styled.div` const StyledInputsContainer = styled.div`
display: flex; display: flex;
@@ -25,7 +25,7 @@ export const SettingsServerlessFunctionNewForm = ({
<TextInput <TextInput
placeholder="Name" placeholder="Name"
fullWidth fullWidth
focused autoFocusOnMount
value={formValues.name} value={formValues.name}
onChange={onChange('name')} onChange={onChange('name')}
/> />

View File

@@ -14,7 +14,8 @@ export type TextInputProps = TextInputV2ComponentProps & {
disableHotkeys?: boolean; disableHotkeys?: boolean;
onInputEnter?: () => void; onInputEnter?: () => void;
dataTestId?: string; dataTestId?: string;
focused?: boolean; autoFocusOnMount?: boolean;
autoSelectOnMount?: boolean;
}; };
export const TextInput = ({ export const TextInput = ({
@@ -22,7 +23,8 @@ export const TextInput = ({
onBlur, onBlur,
onInputEnter, onInputEnter,
disableHotkeys = false, disableHotkeys = false,
focused, autoFocusOnMount,
autoSelectOnMount,
dataTestId, dataTestId,
...props ...props
}: TextInputProps) => { }: TextInputProps) => {
@@ -31,11 +33,17 @@ export const TextInput = ({
const [isFocused, setIsFocused] = useState(false); const [isFocused, setIsFocused] = useState(false);
useEffect(() => { useEffect(() => {
if (focused === true) { if (autoFocusOnMount === true) {
inputRef.current?.focus(); inputRef.current?.focus();
setIsFocused(true); setIsFocused(true);
} }
}, [focused]); }, [autoFocusOnMount]);
useEffect(() => {
if (autoSelectOnMount === true) {
inputRef.current?.select();
}
}, [autoSelectOnMount]);
const { const {
goBackToPreviousHotkeyScope, goBackToPreviousHotkeyScope,