fix(builder): Footer commits in-progress edits on deselect, not just blur (D7)
Footer only committed edited text via onBlur, and its effect rewrote innerText from the (stale) text prop whenever selected became false -- if selection cleared without a real DOM blur, the in-progress edit was silently lost. Adopt Heading.tsx's exact mechanism: an editedTextRef updated on onInput, committed to the prop via an effect keyed on the selected->false transition (in addition to the existing onBlur commit). Preserves the 500ms setProp debounce Footer already had for undo grouping. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -20,16 +20,33 @@ export const Footer: UserComponent<FooterProps> = ({
|
||||
}));
|
||||
|
||||
const elRef = useRef<HTMLElement | null>(null);
|
||||
const editedTextRef = useRef<string | null>(null);
|
||||
|
||||
const handleBlur = useCallback(() => {
|
||||
const commitText = useCallback(() => {
|
||||
if (elRef.current) {
|
||||
const newText = elRef.current.innerText;
|
||||
editedTextRef.current = newText;
|
||||
setProp((p: FooterProps) => { p.text = newText; }, 500);
|
||||
}
|
||||
}, [setProp]);
|
||||
|
||||
// Commit on blur
|
||||
const handleBlur = useCallback(() => { commitText(); }, [commitText]);
|
||||
|
||||
// Also commit on deselect via effect -- covers the case where selection
|
||||
// clears without a real blur (e.g. clicking a different element that
|
||||
// steals selection programmatically), which used to lose the in-progress
|
||||
// edit. Mirrors Heading.tsx's mechanism.
|
||||
useEffect(() => {
|
||||
if (elRef.current && !selected) {
|
||||
if (!selected && editedTextRef.current !== null) {
|
||||
setProp((p: FooterProps) => { p.text = editedTextRef.current!; }, 500);
|
||||
editedTextRef.current = null;
|
||||
}
|
||||
}, [selected, setProp]);
|
||||
|
||||
// Set DOM text on mount and when text prop changes externally (not during editing)
|
||||
useEffect(() => {
|
||||
if (elRef.current && !selected && editedTextRef.current === null) {
|
||||
elRef.current.innerText = text || '';
|
||||
}
|
||||
}, [text, selected]);
|
||||
@@ -43,6 +60,12 @@ export const Footer: UserComponent<FooterProps> = ({
|
||||
contentEditable={selected}
|
||||
suppressContentEditableWarning
|
||||
onBlur={handleBlur}
|
||||
onInput={() => {
|
||||
// Track that we have unsaved edits
|
||||
if (elRef.current) {
|
||||
editedTextRef.current = elRef.current.innerText;
|
||||
}
|
||||
}}
|
||||
style={{
|
||||
padding: '24px 20px',
|
||||
textAlign: 'center',
|
||||
|
||||
Reference in New Issue
Block a user