perf:textarea auto height (#2967)

* perf:textarea auto height

* optimize editor height & fix variable label split
This commit is contained in:
heheer
2024-10-22 18:33:02 +08:00
committed by GitHub
parent 87b4061302
commit 025facbc2d
11 changed files with 100 additions and 46 deletions

View File

@@ -57,6 +57,7 @@
"react-i18next": "14.1.2",
"react-markdown": "^9.0.1",
"react-syntax-highlighter": "^15.5.0",
"react-textarea-autosize": "^8.5.4",
"reactflow": "^11.7.4",
"rehype-external-links": "^3.0.0",
"rehype-katex": "^7.0.0",

View File

@@ -1,4 +1,4 @@
import React, { useRef } from 'react';
import React, { useRef, useState } from 'react';
import {
Box,
@@ -13,11 +13,12 @@ import MyTooltip from '@fastgpt/web/components/common/MyTooltip';
import { useTranslation } from 'next-i18next';
import MyIcon from '@fastgpt/web/components/common/Icon';
import MyModal from '@fastgpt/web/components/common/MyModal';
import ResizeTextarea from 'react-textarea-autosize';
type Props = TextareaProps & {
title?: string;
iconSrc?: string;
// variables: string[];
autoHeight?: boolean;
};
const MyTextarea = React.forwardRef<HTMLTextAreaElement, Props>(function MyTextarea(props, ref) {
@@ -28,6 +29,10 @@ const MyTextarea = React.forwardRef<HTMLTextAreaElement, Props>(function MyTexta
const {
title = t('common:core.app.edit.Prompt Editor'),
iconSrc = 'modal/edit',
autoHeight = false,
onChange,
maxH,
minH,
...childProps
} = props;
@@ -35,16 +40,27 @@ const MyTextarea = React.forwardRef<HTMLTextAreaElement, Props>(function MyTexta
return (
<>
<Editor textareaRef={TextareaRef} {...childProps} onOpenModal={onOpen} />
<Editor
textareaRef={TextareaRef}
autoHeight={autoHeight}
onChange={onChange}
maxH={maxH}
minH={minH}
showResize={!autoHeight}
{...childProps}
onOpenModal={onOpen}
/>
{isOpen && (
<MyModal iconSrc={iconSrc} title={title} isOpen onClose={onClose}>
<ModalBody>
<Editor
textareaRef={ModalTextareaRef}
onChange={onChange}
{...childProps}
minH={'300px'}
maxH={'auto'}
maxH={500}
minH={500}
minW={['100%', '512px']}
showResize={false}
/>
</ModalBody>
<ModalFooter>
@@ -71,17 +87,44 @@ export default React.memo(MyTextarea);
const Editor = React.memo(function Editor({
onOpenModal,
textareaRef,
autoHeight = false,
onChange,
maxH,
minH,
showResize,
...props
}: Props & {
textareaRef: React.RefObject<HTMLTextAreaElement>;
onOpenModal?: () => void;
showResize?: boolean;
}) {
const { t } = useTranslation();
const [scrollHeight, setScrollHeight] = useState(0);
return (
<Box h={'100%'} w={'100%'} position={'relative'}>
<Textarea ref={textareaRef} maxW={'100%'} {...props} />
{onOpenModal && (
<Textarea
ref={textareaRef}
maxW={'100%'}
as={autoHeight ? ResizeTextarea : undefined}
sx={
!showResize
? {
'::-webkit-resizer': {
display: 'none'
}
}
: {}
}
{...props}
maxH={`${maxH}px`}
minH={`${minH}px`}
onChange={(e) => {
setScrollHeight(e.target.scrollHeight);
onChange?.(e);
}}
/>
{onOpenModal && maxH && scrollHeight > Number(maxH) && (
<Box
zIndex={1}
position={'absolute'}

View File

@@ -23,12 +23,12 @@ import { DatasetSearchModeMap } from '@fastgpt/global/core/dataset/constants';
import MyRadio from '@/components/common/MyRadio';
import MyIcon from '@fastgpt/web/components/common/Icon';
import LightRowTabs from '@fastgpt/web/components/common/Tabs/LightRowTabs';
import PromptEditor from '@fastgpt/web/components/common/Textarea/PromptEditor';
import { useUserStore } from '@/web/support/user/useUserStore';
import { useToast } from '@fastgpt/web/hooks/useToast';
import SelectAiModel from '@/components/Select/AIModelSelector';
import QuestionTip from '@fastgpt/web/components/common/MyTooltip/QuestionTip';
import FormLabel from '@fastgpt/web/components/common/MyBox/FormLabel';
import MyTextarea from '@/components/common/Textarea/MyTextarea';
export type DatasetParamsProps = {
searchMode: `${DatasetSearchModeEnum}`;
@@ -317,14 +317,14 @@ const DatasetParamsModal = ({
></QuestionTip>
</Flex>
<Box mt={1}>
<PromptEditor
<MyTextarea
autoHeight
minH={150}
maxH={300}
showOpenModal={false}
placeholder={t('common:core.module.QueryExtension.placeholder')}
value={cfbBgDesc}
onChange={(e) => {
setValue('datasetSearchExtensionBg', e);
setValue('datasetSearchExtensionBg', e.target.value);
}}
/>
</Box>

View File

@@ -24,6 +24,9 @@ const WelcomeTextConfig = (props: TextareaProps) => {
fontSize={'sm'}
bg={'myGray.50'}
placeholder={t('common:core.app.tip.welcomeTextTip')}
autoHeight
minH={100}
maxH={200}
{...props}
/>
</>

View File

@@ -1,11 +1,10 @@
import React, { useCallback, useEffect, useMemo } from 'react';
import React, { useMemo } from 'react';
import { Controller, UseFormReturn } from 'react-hook-form';
import { useTranslation } from 'next-i18next';
import {
Box,
Button,
Card,
Input,
NumberDecrementStepper,
NumberIncrementStepper,
NumberInput,
@@ -24,7 +23,7 @@ import { ChatBoxContext } from '../Provider';
import QuestionTip from '@fastgpt/web/components/common/MyTooltip/QuestionTip';
import { useDeepCompareEffect } from 'ahooks';
import { VariableItemType } from '@fastgpt/global/core/app/type';
import PromptEditor from '@fastgpt/web/components/common/Textarea/PromptEditor';
import MyTextarea from '@/components/common/Textarea/MyTextarea';
export const VariableInputItem = ({
item,
@@ -60,13 +59,13 @@ export const VariableInputItem = ({
{item.description && <QuestionTip ml={1} label={item.description} />}
</Box>
{item.type === VariableInputEnum.input && (
<PromptEditor
value={item.defaultValue}
onChange={(e) => setValue(item.key, e)}
bg={'myGray.50'}
<MyTextarea
autoHeight
minH={40}
maxH={150}
showOpenModal={false}
maxH={160}
bg={'myGray.50'}
value={item.defaultValue}
onChange={(e) => setValue(item.key, e.target.value)}
/>
)}
{item.type === VariableInputEnum.textarea && (

View File

@@ -38,7 +38,7 @@ import { FlowNodeInputTypeEnum } from '@fastgpt/global/core/workflow/node/consta
import { useTranslation } from 'react-i18next';
import { Controller, useForm } from 'react-hook-form';
import MySelect from '@fastgpt/web/components/common/MySelect';
import PromptEditor from '@fastgpt/web/components/common/Textarea/PromptEditor';
import MyTextarea from '@/components/common/Textarea/MyTextarea';
type props = {
value: UserChatItemValueItemType | AIChatItemValueItemType;
@@ -221,12 +221,15 @@ const RenderUserFormInteractive = React.memo(function RenderFormInput({
{input.description && <QuestionTip ml={1} label={input.description} />}
</Flex>
{input.type === FlowNodeInputTypeEnum.input && (
<PromptEditor
value={input.value}
onChange={(e) => setValue(input.label, e)}
<MyTextarea
isDisabled={interactive.params.submitted}
{...register(input.label, {
required: input.required
})}
bg={'white'}
autoHeight
minH={40}
maxH={100}
showOpenModal={false}
/>
)}
{input.type === FlowNodeInputTypeEnum.textarea && (

View File

@@ -33,7 +33,7 @@ import { FlowNodeTypeEnum } from '@fastgpt/global/core/workflow/node/constant';
import { AppContext } from '../../../context';
import { VariableInputItem } from '@/components/core/chat/ChatContainer/ChatBox/components/VariableInput';
import LightRowTabs from '@fastgpt/web/components/common/Tabs/LightRowTabs';
import PromptEditor from '@fastgpt/web/components/common/Textarea/PromptEditor';
import MyTextarea from '@/components/common/Textarea/MyTextarea';
const MyRightDrawer = dynamic(
() => import('@fastgpt/web/components/common/MyDrawer/MyRightDrawer')
@@ -270,16 +270,16 @@ export const useDebug = () => {
const RenderInput = (() => {
if (input.valueType === WorkflowIOValueTypeEnum.string) {
return (
<PromptEditor
<MyTextarea
autoHeight
minH={40}
maxH={160}
bg={'myGray.50'}
placeholder={t(input.placeholder || ('' as any))}
value={getValues(`nodeVariables.${input.key}`)}
onChange={(e) => {
setValue(`nodeVariables.${input.key}`, e);
setValue(`nodeVariables.${input.key}`, e.target.value);
}}
minH={50}
maxH={150}
showOpenModal={false}
placeholder={t(input.placeholder || ('' as any))}
bg={'myGray.50'}
/>
);
}

View File

@@ -34,7 +34,7 @@ import { useFieldArray, UseFormReturn } from 'react-hook-form';
import { useTranslation } from 'react-i18next';
import MyIcon from '@fastgpt/web/components/common/Icon';
import DndDrag, { Draggable } from '@fastgpt/web/components/common/DndDrag';
import PromptEditor from '@fastgpt/web/components/common/Textarea/PromptEditor';
import MyTextarea from '@/components/common/Textarea/MyTextarea';
type ListValueType = { id: string; value: string; label: string }[];
@@ -316,15 +316,12 @@ const InputTypeConfig = ({
</NumberInput>
)}
{inputType === FlowNodeInputTypeEnum.input && (
<PromptEditor
value={defaultValue}
onChange={(e) => {
setValue('defaultValue', e);
}}
minH={40}
maxH={200}
showOpenModal={false}
<MyTextarea
{...register('defaultValue')}
bg={'myGray.50'}
autoHeight
minH={40}
maxH={100}
/>
)}
{inputType === FlowNodeInputTypeEnum.JSONEditor && (

View File

@@ -1,4 +1,4 @@
import React, { Dispatch, useMemo, useState } from 'react';
import React, { Dispatch, useMemo } from 'react';
import { NodeProps } from 'reactflow';
import NodeCard from '../render/NodeCard';
import { FlowNodeItemType } from '@fastgpt/global/core/workflow/type/node.d';
@@ -10,7 +10,7 @@ import MyTextarea from '@/components/common/Textarea/MyTextarea';
import { AppContext } from '../../../../context';
import { AppChatConfigType, AppDetailType } from '@fastgpt/global/core/app/type';
import { getAppChatConfig } from '@fastgpt/global/core/workflow/utils';
import { useCreation, useMount } from 'ahooks';
import { useMount } from 'ahooks';
import ChatFunctionTip from '@/components/core/app/Tip';
import FormLabel from '@fastgpt/web/components/common/MyBox/FormLabel';
import { WorkflowContext } from '../../../context';
@@ -96,6 +96,9 @@ function Instruction({ chatConfig: { instruction }, setAppDetail }: ComponentPro
resize={'both'}
placeholder={t('workflow:plugin.Instruction_Tip')}
value={instruction}
autoHeight
minH={100}
maxH={240}
onChange={(e) => {
setAppDetail((state) => ({
...state,