226cc9eb74
video QA https://github.com/user-attachments/assets/70c37188-2398-43de-bbf6-5882bb79940a --------- Co-authored-by: Charles Bochet <charles@twenty.com>
93 lines
2.2 KiB
TypeScript
93 lines
2.2 KiB
TypeScript
import { TextInput } from '@/ui/input/components/TextInput';
|
|
import styled from '@emotion/styled';
|
|
import { useState } from 'react';
|
|
import { Key } from 'ts-key-enum';
|
|
import { isDefined } from 'twenty-shared/utils';
|
|
import {
|
|
canBeCastAsNumberOrNull,
|
|
castAsNumberOrNull,
|
|
} from '~/utils/cast-as-number-or-null';
|
|
|
|
type CommandMenuItemNumberInputProps = {
|
|
value: string;
|
|
onChange: (value: number | null) => void;
|
|
onValidate?: (value: number | null) => boolean;
|
|
placeholder?: string;
|
|
};
|
|
const StyledRightAlignedTextInput = styled(TextInput)`
|
|
input {
|
|
:focus {
|
|
color: ${({ theme }) => theme.font.color.primary};
|
|
}
|
|
color: ${({ theme }) => theme.font.color.tertiary};
|
|
text-align: right;
|
|
}
|
|
`;
|
|
export const CommandMenuItemNumberInput = ({
|
|
value,
|
|
onChange,
|
|
onValidate,
|
|
placeholder,
|
|
}: CommandMenuItemNumberInputProps) => {
|
|
const [draftValue, setDraftValue] = useState(value);
|
|
const [hasError, setHasError] = useState(false);
|
|
|
|
const handleChange = (text: string) => {
|
|
setDraftValue(text);
|
|
if (hasError) {
|
|
setHasError(false);
|
|
}
|
|
};
|
|
|
|
const handleCommit = () => {
|
|
if (!canBeCastAsNumberOrNull(draftValue)) {
|
|
setHasError(true);
|
|
setDraftValue(value);
|
|
return;
|
|
}
|
|
|
|
const numericValue = castAsNumberOrNull(draftValue);
|
|
|
|
if (isDefined(onValidate)) {
|
|
const isInvalid = onValidate(numericValue);
|
|
if (isInvalid) {
|
|
setHasError(true);
|
|
return;
|
|
}
|
|
}
|
|
|
|
onChange(numericValue);
|
|
setHasError(false);
|
|
};
|
|
|
|
const handleFocus = (event: React.FocusEvent<HTMLInputElement>) => {
|
|
event.target.select();
|
|
};
|
|
|
|
const handleBlur = () => {
|
|
handleCommit();
|
|
};
|
|
|
|
const handleKeyDown = (event: React.KeyboardEvent<HTMLInputElement>) => {
|
|
if (event.key === Key.Enter || event.key === Key.Escape) {
|
|
event.stopPropagation();
|
|
handleCommit();
|
|
} else {
|
|
event.stopPropagation();
|
|
}
|
|
};
|
|
|
|
return (
|
|
<StyledRightAlignedTextInput
|
|
value={draftValue}
|
|
sizeVariant="sm"
|
|
onChange={handleChange}
|
|
onFocus={handleFocus}
|
|
onBlur={handleBlur}
|
|
onKeyDown={handleKeyDown}
|
|
placeholder={placeholder}
|
|
noErrorHelper
|
|
/>
|
|
);
|
|
};
|