Files
FastGPT/packages/web/components/common/Textarea/PromptEditor/Editor.tsx
Archer 34602b25df 4.6.8-alpha (#804)
* perf: redirect request and err log replace

perf: dataset openapi

feat: session

fix: retry input error

feat: 468 doc

sub page

feat: standard sub

perf: rerank tip

perf: rerank tip

perf: api sdk

perf: openapi

sub plan

perf: sub ui

fix: ts

* perf: init log

* fix: variable select

* sub page

* icon

* perf: llm model config

* perf: menu ux

* perf: system store

* perf: publish app name

* fix: init data

* perf: flow edit ux

* fix: value type format and ux

* fix prompt editor default value (#13)

* fix prompt editor default value

* fix prompt editor update when not focus

* add key with variable

---------

Co-authored-by: Archer <545436317@qq.com>

* fix: value type

* doc

* i18n

* import path

* home page

* perf: mongo session running

* fix: ts

* perf: use toast

* perf: flow edit

* perf: sse response

* slider ui

* fetch error

* fix prompt editor rerender when not focus by key defaultvalue (#14)

* perf: prompt editor

* feat: dataset search concat

* perf: doc

* fix:ts

* perf: doc

* fix json editor onblur value (#15)

* faq

* vector model default config

* ipv6

---------

Co-authored-by: heheer <71265218+newfish-cmyk@users.noreply.github.com>
2024-02-01 21:57:41 +08:00

152 lines
4.6 KiB
TypeScript

import { useState, useRef, useTransition, useEffect } from 'react';
import { LexicalComposer } from '@lexical/react/LexicalComposer';
import { PlainTextPlugin } from '@lexical/react/LexicalPlainTextPlugin';
import { ContentEditable } from '@lexical/react/LexicalContentEditable';
import { HistoryPlugin } from '@lexical/react/LexicalHistoryPlugin';
import { OnChangePlugin } from '@lexical/react/LexicalOnChangePlugin';
import LexicalErrorBoundary from '@lexical/react/LexicalErrorBoundary';
import VariablePickerPlugin from './plugins/VariablePickerPlugin';
import { Box } from '@chakra-ui/react';
import styles from './index.module.scss';
import VariablePlugin from './plugins/VariablePlugin';
import { VariableNode } from './plugins/VariablePlugin/node';
import { EditorState, LexicalEditor } from 'lexical';
import OnBlurPlugin from './plugins/OnBlurPlugin';
import MyIcon from '../../Icon';
import { EditorVariablePickerType } from './type.d';
import { getNanoid } from '@fastgpt/global/common/string/tools';
import FocusPlugin from './plugins/FocusPlugin';
import { textToEditorState } from './utils';
export default function Editor({
h = 200,
showResize = true,
showOpenModal = true,
onOpenModal,
variables,
onChange,
onBlur,
value,
placeholder = ''
}: {
h?: number;
showResize?: boolean;
showOpenModal?: boolean;
onOpenModal?: () => void;
variables: EditorVariablePickerType[];
onChange?: (editorState: EditorState) => void;
onBlur?: (editor: LexicalEditor) => void;
value?: string;
placeholder?: string;
}) {
const [key, setKey] = useState(getNanoid(6));
const [_, startSts] = useTransition();
const [height, setHeight] = useState(h);
const [focus, setFocus] = useState(false);
const initialConfig = {
namespace: 'promptEditor',
nodes: [VariableNode],
editorState: textToEditorState(value),
onError: (error: Error) => {
throw error;
}
};
const initialY = useRef(0);
const handleMouseDown = (e: React.MouseEvent) => {
initialY.current = e.clientY;
const handleMouseMove = (e: MouseEvent) => {
const deltaY = e.clientY - initialY.current;
setHeight((prevHeight) => (prevHeight + deltaY < h * 0.5 ? h * 0.5 : prevHeight + deltaY));
initialY.current = e.clientY;
};
const handleMouseUp = () => {
document.removeEventListener('mousemove', handleMouseMove);
document.removeEventListener('mouseup', handleMouseUp);
};
document.addEventListener('mousemove', handleMouseMove);
document.addEventListener('mouseup', handleMouseUp);
};
useEffect(() => {
if (focus) return;
setKey(getNanoid(6));
}, [value, variables, focus]);
return (
<Box position={'relative'} width={'full'} h={`${height}px`} cursor={'text'}>
<LexicalComposer initialConfig={initialConfig} key={key}>
<PlainTextPlugin
contentEditable={<ContentEditable className={styles.contentEditable} />}
placeholder={
<Box
position={'absolute'}
top={0}
left={0}
right={0}
bottom={0}
py={3}
px={4}
pointerEvents={'none'}
overflow={'overlay'}
>
<Box
color={'myGray.500'}
fontSize={'xs'}
userSelect={'none'}
whiteSpace={'pre-wrap'}
wordBreak={'break-all'}
h={'100%'}
>
{placeholder}
</Box>
</Box>
}
ErrorBoundary={LexicalErrorBoundary}
/>
<HistoryPlugin />
<FocusPlugin focus={focus} setFocus={setFocus} />
<OnChangePlugin
onChange={(e) => {
startSts(() => {
onChange?.(e);
});
}}
/>
<VariablePickerPlugin variables={variables} />
<VariablePlugin variables={variables} />
<OnBlurPlugin onBlur={onBlur} />
</LexicalComposer>
{showResize && (
<Box
position={'absolute'}
right={'0'}
bottom={'-1'}
zIndex={9}
cursor={'ns-resize'}
px={'2px'}
onMouseDown={handleMouseDown}
>
<MyIcon name={'common/editor/resizer'} width={'14px'} height={'14px'} />
</Box>
)}
{showOpenModal && (
<Box
zIndex={10}
position={'absolute'}
bottom={1}
right={2}
cursor={'pointer'}
onClick={onOpenModal}
>
<MyIcon name={'common/fullScreenLight'} w={'14px'} color={'myGray.600'} />
</Box>
)}
</Box>
);
}