From 0fc80f7496cb030c9e10e8d69d6f249181ccf45b Mon Sep 17 00:00:00 2001 From: Jeff Emmett Date: Thu, 25 Dec 2025 18:34:52 -0500 Subject: [PATCH] fix: convert props.text to richText for text shape sync (task-026) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Text shapes arriving from other clients had props.text but the deserialization code was initializing richText to empty before deleting props.text, causing content loss. Added text → richText conversion in AutomergeToTLStore.ts before the empty initialization, similar to the existing conversion for geo shapes. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 --- src/automerge/AutomergeToTLStore.ts | 31 +++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/src/automerge/AutomergeToTLStore.ts b/src/automerge/AutomergeToTLStore.ts index 484a215..25e4baa 100644 --- a/src/automerge/AutomergeToTLStore.ts +++ b/src/automerge/AutomergeToTLStore.ts @@ -1159,6 +1159,37 @@ export function sanitizeRecord(record: any): TLRecord { // CRITICAL: Fix richText structure for text shapes - REQUIRED field if (sanitized.type === 'text') { + // CRITICAL: Convert props.text to props.richText for text shapes (fixes sync issue) + // Text shapes may arrive from other clients with props.text instead of props.richText + // We must convert BEFORE initializing richText to empty, otherwise content is lost + if ('text' in sanitized.props && typeof sanitized.props.text === 'string' && sanitized.props.text.trim()) { + const textContent = sanitized.props.text + // Only use text content if richText is missing or empty + const hasRichTextContent = sanitized.props.richText && + typeof sanitized.props.richText === 'object' && + sanitized.props.richText.content && + Array.isArray(sanitized.props.richText.content) && + sanitized.props.richText.content.length > 0 + + if (!hasRichTextContent) { + // Convert text string to richText format for tldraw + sanitized.props.richText = { + type: 'doc', + content: [{ + type: 'paragraph', + content: [{ + type: 'text', + text: textContent + }] + }] + } + console.log(`🔧 AutomergeToTLStore: Converted props.text to richText for text shape ${sanitized.id}`) + } + // Preserve original text in meta for backward compatibility + if (!sanitized.meta) sanitized.meta = {} + sanitized.meta.text = textContent + } + // Text shapes MUST have props.richText as an object - initialize if missing if (!sanitized.props.richText || typeof sanitized.props.richText !== 'object' || sanitized.props.richText === null) { sanitized.props.richText = { content: [], type: 'doc' }