replace @tiptap/html generateJSON with native DOMParser equivalent

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
Samuel Newman
2026-07-08 14:59:40 +03:00
parent ea3d6827c7
commit ff1668671a
@@ -10,6 +10,7 @@ import {StyleSheet, View} from 'react-native'
import Animated, {FadeIn, FadeOut} from 'react-native-reanimated' import Animated, {FadeIn, FadeOut} from 'react-native-reanimated'
import {AppBskyRichtextFacet, RichText} from '@atproto/api' import {AppBskyRichtextFacet, RichText} from '@atproto/api'
import {Trans} from '@lingui/react/macro' import {Trans} from '@lingui/react/macro'
import {getSchema} from '@tiptap/core'
import {Document} from '@tiptap/extension-document' import {Document} from '@tiptap/extension-document'
import Hardbreak from '@tiptap/extension-hard-break' import Hardbreak from '@tiptap/extension-hard-break'
import History from '@tiptap/extension-history' import History from '@tiptap/extension-history'
@@ -17,8 +18,12 @@ import {Mention} from '@tiptap/extension-mention'
import {Paragraph} from '@tiptap/extension-paragraph' import {Paragraph} from '@tiptap/extension-paragraph'
import {Placeholder} from '@tiptap/extension-placeholder' import {Placeholder} from '@tiptap/extension-placeholder'
import {Text as TiptapText} from '@tiptap/extension-text' import {Text as TiptapText} from '@tiptap/extension-text'
import {generateJSON} from '@tiptap/html' import {
import {Fragment, Node, Slice} from '@tiptap/pm/model' DOMParser as ProseMirrorDOMParser,
Fragment,
Node,
Slice,
} from '@tiptap/pm/model'
import {EditorContent, type JSONContent, useEditor} from '@tiptap/react' import {EditorContent, type JSONContent, useEditor} from '@tiptap/react'
import {splitGraphemes} from 'unicode-segmenter/grapheme' import {splitGraphemes} from 'unicode-segmenter/grapheme'
@@ -242,9 +247,7 @@ export function TextInput({
} }
}, },
}, },
content: generateJSON(richTextToHTML(richtext), extensions, { content: richTextToEditorJson(richtext, extensions),
preserveWhitespace: 'full',
}),
autofocus: autoFocus ? 'end' : null, autofocus: autoFocus ? 'end' : null,
editable: true, editable: true,
injectCSS: true, injectCSS: true,
@@ -381,6 +384,26 @@ export function TextInput({
* *
* It also escapes HTML characters * It also escapes HTML characters
*/ */
/*
* Equivalent of @tiptap/html's generateJSON, but using the browser's native
* DOMParser. The @tiptap/html version supports SSR via zeed-dom, which pulls
* ~250KB of parser dependencies into the bundle - we are always in a browser
* here, so we don't need it.
*/
function richTextToEditorJson(
richtext: RichText,
extensions: Parameters<typeof getSchema>[0],
): JSONContent {
const schema = getSchema(extensions)
const dom = new DOMParser().parseFromString(
richTextToHTML(richtext),
'text/html',
).body
return ProseMirrorDOMParser.fromSchema(schema)
.parse(dom, {preserveWhitespace: 'full'})
.toJSON()
}
function richTextToHTML(richtext: RichText): string { function richTextToHTML(richtext: RichText): string {
let html = '' let html = ''
@@ -392,7 +415,9 @@ function richTextToHTML(richtext: RichText): string {
} }
} }
return html // the body wrapper preserves leading whitespace, which the parser
// otherwise strips
return `<body>${html}</body>`
} }
function escapeHTML(str: string): string { function escapeHTML(str: string): string {