import React, { useState, useCallback, useEffect } from 'react'; import { EditorContent, useEditor } from '@tiptap/react'; import StarterKit from '@tiptap/starter-kit'; import { motion } from "framer-motion"; import { CharacterTokenExtension } from './CharacterToken'; import { ShotTitle } from './ShotTitle'; import { ReadonlyText } from './ReadonlyText'; const initialContent = { type: 'doc', content: [ { type: 'shotTitle', attrs: { title: `分镜1` }, }, { type: 'paragraph', content: [ { type: 'characterToken', attrs: { name: '张三', gender: '男', age: '28', avatar: 'https://i.pravatar.cc/40?u=z3' }}, { type: 'text', text: ' 从门口走来,皱着眉头说:“你怎么还在这里?”' } ] }, { type: 'shotTitle', attrs: { title: `分镜2` }, }, { type: 'paragraph', content: [ { type: 'characterToken', attrs: { name: '李四', gender: '女', age: '26', avatar: 'https://i.pravatar.cc/40?u=l4' }}, { type: 'text', text: ' 微微低头,没有说话。' } ] } ] }; interface ShotEditorProps { onAddSegment?: () => void; onCharacterClick?: (attrs: any) => void; } const ShotEditor = React.forwardRef<{ addSegment: () => void, onCharacterClick: (attrs: any) => void }, ShotEditorProps>(function ShotEditor({ onAddSegment, onCharacterClick }, ref) { const [segments, setSegments] = useState(initialContent.content); const editor = useEditor({ extensions: [ StarterKit, CharacterTokenExtension, ShotTitle, ReadonlyText, ], content: { type: 'doc', content: segments }, editorProps: { attributes: { class: 'prose prose-invert max-w-none min-h-[150px] focus:outline-none' } }, immediatelyRender: false, onCreate: ({ editor }) => { editor.setOptions({ editable: true }) }, }) useEffect(() => { const handleCharacterClick = (attrs: any) => { console.log('SceneEditor 收到角色点击事件:', attrs) // 你可以这里 setState 打开一个弹窗 / 面板等 onCharacterClick?.(attrs); }; editor?.on('character-clicked', handleCharacterClick as any); return () => { editor?.off('character-clicked', handleCharacterClick as any); }; }, [editor]); const addSegment = () => { if (!editor) return; // 自动编号(获取已有 shotTitle 节点数量) const doc = editor.state.doc; let shotCount = 0; doc.descendants((node) => { if (node.type.name === 'paragraph') { shotCount++; } }); editor.chain().focus('end').insertContent([ { type: 'shotTitle', attrs: { title: `分镜${shotCount + 1}` }, }, { type: 'paragraph', content: [ { type: 'text', text: '镜头描述' } ] } ]) .focus('end') // 聚焦到文档末尾 .run(); // 调用外部传入的回调函数 onAddSegment?.(); }; // 暴露 addSegment 方法给父组件 React.useImperativeHandle(ref, () => ({ addSegment })); if (!editor) { return null } return (