Skip to content

Commit 2794a4c

Browse files
committed
fix: 文本编辑时实时同步底层渲染
1 parent 4d98e8b commit 2794a4c

File tree

2 files changed

+36
-2
lines changed

2 files changed

+36
-2
lines changed

src/components/SlideRenderer.tsx

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,7 @@ export function SlideRenderer({
6363
const isDraggingRef = useRef(false)
6464
const isResizingRef = useRef(false)
6565
const [editingTextElementId, setEditingTextElementId] = useState<string | null>(null)
66+
const [draftTextLinesMap, setDraftTextLinesMap] = useState<Record<string, TextLine[]>>({})
6667
const backgroundImageUrl = slide.backgroundImage ? resourceMap[slide.backgroundImage] : null
6768
const scaledWidth = slide.width * scale
6869
const scaledHeight = slide.height * scale
@@ -113,16 +114,19 @@ export function SlideRenderer({
113114
useEffect(() => {
114115
if (!isEditMode) {
115116
setEditingTextElementId(null)
117+
setDraftTextLinesMap({})
116118
}
117119
}, [isEditMode, slide.id])
118120

119121
useEffect(() => {
120122
if (!selectedElementId) {
121123
setEditingTextElementId(null)
124+
setDraftTextLinesMap({})
122125
return
123126
}
124127
if (editingTextElementId && selectedElementId !== editingTextElementId) {
125128
setEditingTextElementId(null)
129+
setDraftTextLinesMap({})
126130
}
127131
}, [editingTextElementId, selectedElementId])
128132

@@ -309,6 +313,9 @@ export function SlideRenderer({
309313
{slide.elements.map(element => {
310314
if (elementRenderStates[element.id] === false) return null
311315
const bounds = resolveElementBounds(element)
316+
const renderedElement = element.type === 'text' && draftTextLinesMap[element.id]
317+
? { ...element, textLines: draftTextLinesMap[element.id] }
318+
: element
312319
return (
313320
<div
314321
key={element.id}
@@ -345,7 +352,7 @@ export function SlideRenderer({
345352
}}
346353
>
347354
<ElementRenderer
348-
element={element}
355+
element={renderedElement}
349356
scale={1}
350357
resourceMap={resourceMap}
351358
slideIndex={slideIndex}
@@ -356,9 +363,27 @@ export function SlideRenderer({
356363
<EditableTextOverlay
357364
element={element}
358365
onCancel={() => {
366+
setDraftTextLinesMap(prev => {
367+
if (!prev[element.id]) return prev
368+
const next = { ...prev }
369+
delete next[element.id]
370+
return next
371+
})
359372
setEditingTextElementId(null)
360373
}}
374+
onLiveChange={nextTextLines => {
375+
setDraftTextLinesMap(prev => ({
376+
...prev,
377+
[element.id]: nextTextLines
378+
}))
379+
}}
361380
onCommit={nextTextLines => {
381+
setDraftTextLinesMap(prev => {
382+
if (!prev[element.id]) return prev
383+
const next = { ...prev }
384+
delete next[element.id]
385+
return next
386+
})
362387
onEditTextUpdate?.(element.id, nextTextLines)
363388
setEditingTextElementId(null)
364389
}}

src/components/slide-renderer/EditableTextOverlay.tsx

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ interface EditableTextOverlayProps {
88
element: TextElement
99
onCommit: (nextTextLines: TextLine[]) => void
1010
onCancel: () => void
11+
onLiveChange?: (nextTextLines: TextLine[]) => void
1112
}
1213

1314
interface TextSegment {
@@ -156,7 +157,7 @@ function buildEditableTextLines(root: HTMLDivElement, sourceLines: TextLine[]):
156157
return nextLines
157158
}
158159

159-
export function EditableTextOverlay({ element, onCommit, onCancel }: EditableTextOverlayProps) {
160+
export function EditableTextOverlay({ element, onCommit, onCancel, onLiveChange }: EditableTextOverlayProps) {
160161
const editorRef = useRef<HTMLDivElement | null>(null)
161162
const hasCommittedRef = useRef(false)
162163

@@ -206,6 +207,13 @@ export function EditableTextOverlay({ element, onCommit, onCancel }: EditableTex
206207
commit()
207208
}
208209

210+
const handleInput = () => {
211+
const editor = editorRef.current
212+
if (!editor || !onLiveChange) return
213+
const nextTextLines = buildEditableTextLines(editor, element.textLines)
214+
onLiveChange(nextTextLines)
215+
}
216+
209217
const handleKeyDown = (event: React.KeyboardEvent<HTMLDivElement>) => {
210218
if (event.key === 'Escape') {
211219
event.preventDefault()
@@ -238,6 +246,7 @@ export function EditableTextOverlay({ element, onCommit, onCancel }: EditableTex
238246
suppressContentEditableWarning
239247
spellCheck={false}
240248
onBlur={handleBlur}
249+
onInput={handleInput}
241250
onKeyDown={handleKeyDown}
242251
style={{
243252
width: '100%',

0 commit comments

Comments
 (0)