121 lines
2.9 KiB
TypeScript
121 lines
2.9 KiB
TypeScript
/*
|
||
* Copyright 2025 coze-dev Authors
|
||
*
|
||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||
* you may not use this file except in compliance with the License.
|
||
* You may obtain a copy of the License at
|
||
*
|
||
* http://www.apache.org/licenses/LICENSE-2.0
|
||
*
|
||
* Unless required by applicable law or agreed to in writing, software
|
||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||
* See the License for the specific language governing permissions and
|
||
* limitations under the License.
|
||
*/
|
||
|
||
/* eslint-disable @typescript-eslint/no-explicit-any */
|
||
import {
|
||
useRef,
|
||
useImperativeHandle,
|
||
forwardRef,
|
||
useState,
|
||
useEffect,
|
||
} from 'react';
|
||
|
||
import { TextArea, withField } from '@coze-arch/coze-design';
|
||
|
||
import {
|
||
type EditorInputProps,
|
||
type EditorHandle,
|
||
type Editor,
|
||
type Delta,
|
||
} from './types';
|
||
|
||
export const EditorFullInputInner = forwardRef<EditorHandle, EditorInputProps>(
|
||
(props: EditorInputProps, ref) => {
|
||
const {
|
||
value: propsValue,
|
||
onChange: propsOnChange,
|
||
getEditor,
|
||
...restProps
|
||
} = props;
|
||
const [value, setValue] = useState(propsValue);
|
||
|
||
// 创建一个可变引用以存储最新的value值
|
||
const valueRef = useRef(value);
|
||
|
||
// 当value更新时,同步更新valueRef
|
||
useEffect(() => {
|
||
valueRef.current = value;
|
||
}, [value]);
|
||
|
||
const editorRef = useRef<Editor>({
|
||
setHTML: (htmlContent: string) => {
|
||
setValue(htmlContent);
|
||
},
|
||
setText: (text: string) => {
|
||
setValue(text);
|
||
},
|
||
setContent: (content: { deltas: Delta[] }) => {
|
||
setValue(content.deltas[0].insert);
|
||
},
|
||
getContent: () => ({
|
||
deltas: [{ insert: valueRef.current ?? '' }],
|
||
}),
|
||
getText: () => valueRef.current || '',
|
||
getRootContainer: () => null,
|
||
getContentState: () => ({
|
||
getZoneState: (zone: any) => null,
|
||
}),
|
||
selection: {
|
||
getSelection: () => ({
|
||
start: 0,
|
||
end: 0,
|
||
zoneId: '0',
|
||
}),
|
||
},
|
||
registerCommand: () => null,
|
||
scrollModule: {
|
||
scrollTo: () => null,
|
||
},
|
||
on: () => null,
|
||
});
|
||
|
||
useImperativeHandle(ref, () => ({
|
||
setDeltaContent(delta) {
|
||
editorRef.current && delta && editorRef.current.setContent(delta);
|
||
},
|
||
getEditor() {
|
||
return editorRef.current;
|
||
},
|
||
getMarkdown() {
|
||
return editorRef.current?.getText() || '';
|
||
},
|
||
}));
|
||
|
||
useEffect(() => {
|
||
getEditor?.(editorRef.current);
|
||
}, [getEditor]);
|
||
|
||
return (
|
||
<TextArea
|
||
{...restProps}
|
||
value={value}
|
||
onChange={v => {
|
||
setValue(v);
|
||
propsOnChange?.(v);
|
||
}}
|
||
/>
|
||
);
|
||
},
|
||
);
|
||
|
||
export const EditorInput: typeof EditorFullInputInner = withField(
|
||
EditorFullInputInner,
|
||
{
|
||
valueKey: 'value',
|
||
onKeyChangeFnName: 'onChange',
|
||
},
|
||
);
|