замена инпут на текстареа
This commit is contained in:
parent
426449d9bf
commit
70cc2e4e5b
@ -1,3 +1,4 @@
|
||||
1.0.7 _ 2025-10-05 _ замена инпут на текстареа
|
||||
1.0.6 _ 2025-09-19 _ логика включения таймера
|
||||
1.0.5 _ 2025-09-18 _ особые условия для вывода картинок
|
||||
1.0.4 _ 2025-09-14 _ особые условия для вывода картинок
|
||||
|
||||
@ -39,22 +39,31 @@ const AnswerItem = memo<AnswerItemProps>(
|
||||
const isTablet = useMediaQuery(theme.breakpoints.down(790));
|
||||
|
||||
const setOwnPlaceholder = (replText: string) => {
|
||||
updateQuestion(questionId, (question) => {
|
||||
updateQuestion<QuizQuestionVariant>(questionId, (question) => {
|
||||
question.content.ownPlaceholder = replText;
|
||||
});
|
||||
};
|
||||
|
||||
const inputRefCallback = useCallback((element: HTMLInputElement | null) => {
|
||||
const inputRefCallback = useCallback((element: HTMLInputElement | HTMLTextAreaElement | null) => {
|
||||
if (element && shouldAutoFocus) {
|
||||
element.focus();
|
||||
onFocusHandled?.();
|
||||
}
|
||||
}, [shouldAutoFocus, onFocusHandled]);
|
||||
|
||||
const handleKeyDown = (event: KeyboardEvent<HTMLInputElement>) => {
|
||||
const handleKeyDown = (event: KeyboardEvent<HTMLDivElement>) => {
|
||||
// Shift+Enter — новая строка, ничего не делаем (даём браузеру вставить перенос)
|
||||
if (event.key === "Enter" && event.shiftKey) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Enter — добавить новый вариант
|
||||
if (event.key === "Enter") {
|
||||
event.preventDefault();
|
||||
if (disableKeyDown) {
|
||||
enqueueSnackbar("100 максимальное количество");
|
||||
} else if (event.code === "Enter" && !largeCheck) {
|
||||
return;
|
||||
}
|
||||
if (onEnterKeyPress) {
|
||||
onEnterKeyPress();
|
||||
} else {
|
||||
@ -92,8 +101,9 @@ const AnswerItem = memo<AnswerItemProps>(
|
||||
fullWidth
|
||||
focused={false}
|
||||
placeholder={isOwn ? "Добавьте текст-подсказку для ввода \"своего ответа\"" : "Добавьте ответ"}
|
||||
multiline={largeCheck}
|
||||
onChange={({ target }: ChangeEvent<HTMLInputElement>) => {
|
||||
multiline
|
||||
rows={1}
|
||||
onChange={({ target }: ChangeEvent<HTMLInputElement | HTMLTextAreaElement>) => {
|
||||
if (target.value.length <= 1000) {
|
||||
isOwn ?
|
||||
setOwnPlaceholder(target.value || " ")
|
||||
@ -148,6 +158,9 @@ const AnswerItem = memo<AnswerItemProps>(
|
||||
},
|
||||
"& textarea.MuiInputBase-input": {
|
||||
marginTop: "1px",
|
||||
resize: "none",
|
||||
// удерживаем стартовую высоту визуально как у однострочного
|
||||
lineHeight: "21px",
|
||||
},
|
||||
"& .MuiOutlinedInput-notchedOutline": {
|
||||
border: "none",
|
||||
|
||||
@ -51,7 +51,7 @@ export default function DropDown({ question, openBranchingPage, setOpenBranching
|
||||
questionId={question.id}
|
||||
variant={variant}
|
||||
isOwn={Boolean(variant?.isOwn)}
|
||||
ownPlaceholder={question.content.ownPlaceholder || ""}
|
||||
ownPlaceholder={""}
|
||||
shouldAutoFocus={focusedVariantId === variant.id}
|
||||
onFocusHandled={clearFocusedVariant}
|
||||
onEnterKeyPress={() => addVariantOnEnter(question.id)}
|
||||
@ -59,13 +59,8 @@ export default function DropDown({ question, openBranchingPage, setOpenBranching
|
||||
))}
|
||||
/>
|
||||
)}
|
||||
<Box
|
||||
sx={{
|
||||
display: "flex",
|
||||
alignItems: "center",
|
||||
marginBottom: "20px",
|
||||
}}
|
||||
>
|
||||
<Box sx={{ display: "flex", flexDirection: "column", alignItems: "flex-start", marginBottom: "20px" }}>
|
||||
<Box sx={{ display: "flex", alignItems: "center" }}>
|
||||
<Link
|
||||
component="button"
|
||||
variant="body2"
|
||||
@ -102,6 +97,20 @@ export default function DropDown({ question, openBranchingPage, setOpenBranching
|
||||
</>
|
||||
)}
|
||||
</Box>
|
||||
{isMobile ? null : (
|
||||
<Typography
|
||||
sx={{
|
||||
fontWeight: 400,
|
||||
lineHeight: "21.33px",
|
||||
color: theme.palette.grey2.main,
|
||||
fontSize: "16px",
|
||||
mt: "4px",
|
||||
}}
|
||||
>
|
||||
нажмите shift + enter для переноса строки
|
||||
</Typography>
|
||||
)}
|
||||
</Box>
|
||||
</Box>
|
||||
<ButtonsOptions
|
||||
switchState={switchState}
|
||||
@ -110,6 +119,7 @@ export default function DropDown({ question, openBranchingPage, setOpenBranching
|
||||
questionContentId={question.content.id}
|
||||
questionType={question.type}
|
||||
questionHasParent={question.content.rule.parentId?.length !== 0}
|
||||
openBranchingPage={openBranchingPage}
|
||||
setOpenBranchingPage={setOpenBranchingPage}
|
||||
/>
|
||||
<SwitchDropDown
|
||||
|
||||
@ -47,7 +47,7 @@ export default function Emoji({ question, openBranchingPage, setOpenBranchingPag
|
||||
setOpen={setOpen}
|
||||
setSelectedVariant={setSelectedVariant}
|
||||
isOwn={Boolean(variant?.isOwn)}
|
||||
ownPlaceholder={question.content.ownPlaceholder}
|
||||
ownPlaceholder={question.content.ownPlaceholder || ""}
|
||||
shouldAutoFocus={focusedVariantId === variant.id}
|
||||
onFocusHandled={clearFocusedVariant}
|
||||
onEnterKeyPress={() => addVariantOnEnter(question.id)}
|
||||
@ -84,14 +84,8 @@ export default function Emoji({ question, openBranchingPage, setOpenBranchingPag
|
||||
}}
|
||||
/>
|
||||
</Popover>
|
||||
<Box
|
||||
sx={{
|
||||
display: "flex",
|
||||
alignItems: "center",
|
||||
gap: "10px",
|
||||
marginBottom: isMobile ? "17px" : "20px",
|
||||
}}
|
||||
>
|
||||
<Box sx={{ display: "flex", flexDirection: "column", alignItems: "flex-start", marginBottom: isMobile ? "17px" : "20px" }}>
|
||||
<Box sx={{ display: "flex", alignItems: "center" }}>
|
||||
<Link
|
||||
component="button"
|
||||
variant="body2"
|
||||
@ -122,6 +116,20 @@ export default function Emoji({ question, openBranchingPage, setOpenBranchingPag
|
||||
</>
|
||||
)}
|
||||
</Box>
|
||||
{!isTablet && (
|
||||
<Typography
|
||||
sx={{
|
||||
fontWeight: 400,
|
||||
lineHeight: "21.33px",
|
||||
color: theme.palette.grey2.main,
|
||||
fontSize: "16px",
|
||||
mt: "4px",
|
||||
}}
|
||||
>
|
||||
для переноса строки нажмите shift + enter
|
||||
</Typography>
|
||||
)}
|
||||
</Box>
|
||||
</Box>
|
||||
<ButtonsOptions
|
||||
switchState={switchState}
|
||||
@ -130,6 +138,7 @@ export default function Emoji({ question, openBranchingPage, setOpenBranchingPag
|
||||
questionContentId={question.content.id}
|
||||
questionType={question.type}
|
||||
questionHasParent={question.content.rule.parentId?.length !== 0}
|
||||
openBranchingPage={openBranchingPage}
|
||||
setOpenBranchingPage={setOpenBranchingPage}
|
||||
/>
|
||||
<SwitchEmoji
|
||||
|
||||
@ -134,13 +134,8 @@ export default function OptionsAndPicture({
|
||||
selfClose={() => setOpenCropModal(false)}
|
||||
setPictureUploading={setPictureUploading}
|
||||
/>
|
||||
<Box
|
||||
sx={{
|
||||
display: "flex",
|
||||
alignItems: "center",
|
||||
marginBottom: "17px",
|
||||
}}
|
||||
>
|
||||
<Box sx={{ display: "flex", flexDirection: "column", alignItems: "flex-start", marginBottom: "17px" }}>
|
||||
<Box sx={{ display: "flex", alignItems: "center" }}>
|
||||
<Link
|
||||
component="button"
|
||||
variant="body2"
|
||||
@ -179,6 +174,20 @@ export default function OptionsAndPicture({
|
||||
</>
|
||||
)}
|
||||
</Box>
|
||||
{isMobile ? null : (
|
||||
<Typography
|
||||
sx={{
|
||||
fontWeight: 400,
|
||||
lineHeight: "21.33px",
|
||||
color: theme.palette.grey2.main,
|
||||
fontSize: "16px",
|
||||
mt: "4px",
|
||||
}}
|
||||
>
|
||||
для переноса строки нажмите shift + enter
|
||||
</Typography>
|
||||
)}
|
||||
</Box>
|
||||
</Box>
|
||||
<ButtonsOptions
|
||||
switchState={switchState}
|
||||
|
||||
@ -87,12 +87,12 @@ export default function OptionsPicture({
|
||||
largeCheck={question.content.largeCheck}
|
||||
variant={variant}
|
||||
isMobile={isMobile}
|
||||
openCropModal={() => {setOpenCropModal(true)}}
|
||||
openCropModal={() => { setOpenCropModal(true); return Promise.resolve(); }}
|
||||
openImageUploadModal={openImageUploadModal}
|
||||
pictureUploding={pictureUploding}
|
||||
setSelectedVariantId={setSelectedVariantId}
|
||||
isOwn={Boolean(variant?.isOwn)}
|
||||
ownPlaceholder={question.content.ownPlaceholder}
|
||||
ownPlaceholder={question.content.ownPlaceholder || ""}
|
||||
shouldAutoFocus={focusedVariantId === variant.id}
|
||||
onFocusHandled={clearFocusedVariant}
|
||||
onEnterKeyPress={() => addVariantOnEnter(question.id)}
|
||||
@ -105,17 +105,18 @@ export default function OptionsPicture({
|
||||
handleImageChange={handleImageUpload}
|
||||
/>
|
||||
<CropModalInit
|
||||
originalImageUrl={variant?.originalImageUrl}
|
||||
editedUrlImagesList={variant?.editedUrlImagesList}
|
||||
originalImageUrl={variant?.originalImageUrl ?? ""}
|
||||
editedUrlImagesList={(variant?.editedUrlImagesList as any) ?? undefined}
|
||||
questionId={question.id.toString()}
|
||||
questionType={question.type}
|
||||
quizId={quizQid}
|
||||
variantId={variant?.id}
|
||||
questionType={question.type as any}
|
||||
quizId={quizQid ?? ""}
|
||||
variantId={variant?.id ?? ""}
|
||||
open={openCropModal}
|
||||
selfClose={() => setOpenCropModal(false)}
|
||||
setPictureUploading={setPictureUploading}
|
||||
setPictureUploading={setPictureUploading as any}
|
||||
/>
|
||||
<Box sx={{ display: "flex", alignItems: "center", gap: "10px" }}>
|
||||
<Box sx={{ display: "flex", flexDirection: "column", alignItems: "flex-start" }}>
|
||||
<Box sx={{ display: "flex", alignItems: "center" }}>
|
||||
<Link
|
||||
component="button"
|
||||
variant="body2"
|
||||
@ -146,6 +147,20 @@ export default function OptionsPicture({
|
||||
</>
|
||||
)}
|
||||
</Box>
|
||||
{isMobile ? null : (
|
||||
<Typography
|
||||
sx={{
|
||||
fontWeight: 400,
|
||||
lineHeight: "21.33px",
|
||||
color: theme.palette.grey2.main,
|
||||
fontSize: "16px",
|
||||
mt: "4px",
|
||||
}}
|
||||
>
|
||||
для переноса строки нажмите shift + enter
|
||||
</Typography>
|
||||
)}
|
||||
</Box>
|
||||
</Box>
|
||||
<ButtonsOptions
|
||||
switchState={switchState}
|
||||
@ -154,11 +169,12 @@ export default function OptionsPicture({
|
||||
questionContentId={question.content.id}
|
||||
questionType={question.type}
|
||||
questionHasParent={question.content.rule.parentId?.length !== 0}
|
||||
openBranchingPage={openBranchingPage}
|
||||
setOpenBranchingPage={setOpenBranchingPage}
|
||||
/>
|
||||
<SwitchAnswerOptionsPict
|
||||
switchState={switchState}
|
||||
question={question}
|
||||
question={question as any}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
|
||||
@ -54,7 +54,7 @@ export default function AnswerOptions({ question, openBranchingPage, setOpenBran
|
||||
questionId={question.id}
|
||||
variant={variant}
|
||||
isOwn={Boolean(variant.isOwn)}
|
||||
ownPlaceholder={question.content.ownPlaceholder}
|
||||
ownPlaceholder={question.content.ownPlaceholder || ""}
|
||||
shouldAutoFocus={focusedVariantId === variant.id}
|
||||
onFocusHandled={clearFocusedVariant}
|
||||
onEnterKeyPress={() => addVariantOnEnter(question.id)}
|
||||
@ -63,13 +63,8 @@ export default function AnswerOptions({ question, openBranchingPage, setOpenBran
|
||||
/>
|
||||
)}
|
||||
|
||||
<Box
|
||||
sx={{
|
||||
display: "flex",
|
||||
alignItems: "center",
|
||||
marginBottom: "17px",
|
||||
}}
|
||||
>
|
||||
<Box sx={{ display: "flex", flexDirection: "column", alignItems: "flex-start", marginBottom: "17px" }}>
|
||||
<Box sx={{ display: "flex", alignItems: "center" }}>
|
||||
<Link
|
||||
component="button"
|
||||
variant="body2"
|
||||
@ -106,6 +101,20 @@ export default function AnswerOptions({ question, openBranchingPage, setOpenBran
|
||||
</>
|
||||
)}
|
||||
</Box>
|
||||
{isMobile ? null : (
|
||||
<Typography
|
||||
sx={{
|
||||
fontWeight: 400,
|
||||
lineHeight: "21.33px",
|
||||
color: theme.palette.grey2.main,
|
||||
fontSize: "16px",
|
||||
mt: "4px",
|
||||
}}
|
||||
>
|
||||
для переноса строки нажмите shift + enter
|
||||
</Typography>
|
||||
)}
|
||||
</Box>
|
||||
</Box>
|
||||
<ButtonsOptions
|
||||
switchState={switchState}
|
||||
|
||||
@ -17,12 +17,12 @@ interface CustomTextFieldProps {
|
||||
value?: string;
|
||||
error?: string;
|
||||
emptyError?: boolean;
|
||||
onChange?: (event: ChangeEvent<HTMLInputElement>) => void;
|
||||
onKeyDown?: (event: KeyboardEvent<HTMLInputElement>) => void;
|
||||
onBlur?: (event: FocusEvent<HTMLInputElement>) => void;
|
||||
onFocus?: (event: FocusEvent<HTMLInputElement>) => void;
|
||||
onClick?: (event: MouseEvent<HTMLInputElement>) => void;
|
||||
onPaste?: (event: ClipboardEvent<HTMLInputElement>) => void;
|
||||
onChange?: (event: ChangeEvent<HTMLInputElement | HTMLTextAreaElement>) => void;
|
||||
onKeyDown?: (event: KeyboardEvent<HTMLInputElement | HTMLTextAreaElement>) => void;
|
||||
onBlur?: (event: FocusEvent<HTMLInputElement | HTMLTextAreaElement>) => void;
|
||||
onFocus?: (event: FocusEvent<HTMLInputElement | HTMLTextAreaElement>) => void;
|
||||
onClick?: (event: MouseEvent<HTMLInputElement | HTMLTextAreaElement>) => void;
|
||||
onPaste?: (event: ClipboardEvent<HTMLInputElement | HTMLTextAreaElement>) => void;
|
||||
text?: string;
|
||||
maxLength?: number;
|
||||
sx?: SxProps<Theme>;
|
||||
@ -32,7 +32,7 @@ interface CustomTextFieldProps {
|
||||
rows?: number;
|
||||
className?: string;
|
||||
disabled?: boolean;
|
||||
inputRef?: Ref<HTMLInputElement>;
|
||||
inputRef?: Ref<HTMLInputElement | HTMLTextAreaElement>;
|
||||
}
|
||||
|
||||
export default function CustomTextField({
|
||||
@ -67,7 +67,9 @@ export default function CustomTextField({
|
||||
setInputValue(value);
|
||||
}, [value]);
|
||||
|
||||
const handleInputChange = (event: React.ChangeEvent<HTMLInputElement>) => {
|
||||
const handleInputChange = (
|
||||
event: React.ChangeEvent<HTMLInputElement | HTMLTextAreaElement>
|
||||
) => {
|
||||
if (event.target.value.length <= maxLength) {
|
||||
const inputValue = event.target.value;
|
||||
|
||||
@ -85,12 +87,16 @@ export default function CustomTextField({
|
||||
}
|
||||
};
|
||||
|
||||
const handleInputFocus = (event: React.FocusEvent<HTMLInputElement>) => {
|
||||
const handleInputFocus = (
|
||||
event: React.FocusEvent<HTMLInputElement | HTMLTextAreaElement>
|
||||
) => {
|
||||
setIsInputActive(true);
|
||||
if (onFocus) onFocus(event);
|
||||
};
|
||||
|
||||
const handleInputBlur = (event: React.FocusEvent<HTMLInputElement>) => {
|
||||
const handleInputBlur = (
|
||||
event: React.FocusEvent<HTMLInputElement | HTMLTextAreaElement>
|
||||
) => {
|
||||
setIsInputActive(false);
|
||||
|
||||
if (onBlur) {
|
||||
@ -98,6 +104,12 @@ export default function CustomTextField({
|
||||
}
|
||||
};
|
||||
|
||||
const mergedInputElementProps = {
|
||||
...(InputProps?.inputProps as any),
|
||||
onClick,
|
||||
onPaste,
|
||||
};
|
||||
|
||||
return (
|
||||
<FormControl
|
||||
fullWidth
|
||||
@ -126,14 +138,13 @@ export default function CustomTextField({
|
||||
onFocus={handleInputFocus}
|
||||
onBlur={handleInputBlur}
|
||||
onKeyDown={onKeyDown}
|
||||
onClick={onClick}
|
||||
onPaste={onPaste}
|
||||
multiline={rows > 0}
|
||||
rows={rows}
|
||||
multiline
|
||||
rows={rows > 0 ? rows : 1}
|
||||
disabled={disabled}
|
||||
disableUnderline
|
||||
inputRef={inputRef}
|
||||
{...InputProps}
|
||||
inputProps={mergedInputElementProps}
|
||||
sx={{
|
||||
maxLength: maxLength,
|
||||
borderRadius: "10px",
|
||||
@ -143,6 +154,8 @@ export default function CustomTextField({
|
||||
border: `${isInputActive ? "black 2px" : "#9A9AAF 1px"} solid`,
|
||||
backgroundColor: theme.palette.background.default,
|
||||
height: "48px",
|
||||
// Prevent resize handle to keep visuals unchanged
|
||||
'& textarea': { resize: 'none' },
|
||||
...sx,
|
||||
}}
|
||||
data-cy="textfield"
|
||||
|
||||
Loading…
Reference in New Issue
Block a user