diff --git a/package.json b/package.json index 61c20d2f58..32ca3de7aa 100644 --- a/package.json +++ b/package.json @@ -63,6 +63,7 @@ "@tiptap/extension-paragraph": "^2.0.0-beta.220", "@tiptap/extension-placeholder": "^2.0.0-beta.220", "@tiptap/extension-text": "^2.0.0-beta.220", + "@tiptap/html": "^2.1.11", "@tiptap/pm": "^2.0.0-beta.220", "@tiptap/react": "^2.0.0-beta.220", "@tiptap/suggestion": "^2.0.0-beta.220", diff --git a/src/view/com/composer/text-input/TextInput.web.tsx b/src/view/com/composer/text-input/TextInput.web.tsx index 7eea904ab0..31e372567f 100644 --- a/src/view/com/composer/text-input/TextInput.web.tsx +++ b/src/view/com/composer/text-input/TextInput.web.tsx @@ -17,6 +17,7 @@ import {useColorSchemeStyle} from 'lib/hooks/useColorSchemeStyle' import {isUriImage, blobToDataUri} from 'lib/media/util' import {Emoji} from './web/EmojiPicker.web' import {LinkDecorator} from './web/LinkDecorator' +import {generateJSON} from '@tiptap/html' export interface TextInputRef { focus: () => void @@ -52,6 +53,26 @@ export const TextInput = React.forwardRef(function TextInputImpl( ref, ) { const modeClass = useColorSchemeStyle('ProseMirror-light', 'ProseMirror-dark') + const extensions = React.useMemo( + () => [ + Document, + LinkDecorator, + Mention.configure({ + HTMLAttributes: { + class: 'mention', + }, + suggestion: createSuggestion({autocompleteView}), + }), + Paragraph, + Placeholder.configure({ + placeholder, + }), + Text, + History, + Hardbreak, + ], + [autocompleteView, placeholder], + ) React.useEffect(() => { textInputWebEmitter.addListener('publish', onPressPublish) @@ -68,23 +89,7 @@ export const TextInput = React.forwardRef(function TextInputImpl( const editor = useEditor( { - extensions: [ - Document, - LinkDecorator, - Mention.configure({ - HTMLAttributes: { - class: 'mention', - }, - suggestion: createSuggestion({autocompleteView}), - }), - Paragraph, - Placeholder.configure({ - placeholder, - }), - Text, - History, - Hardbreak, - ], + extensions, editorProps: { attributes: { class: modeClass, @@ -107,7 +112,7 @@ export const TextInput = React.forwardRef(function TextInputImpl( } }, }, - content: textToEditorJson(richtext.text.toString()), + content: generateJSON(richtext.text.toString(), extensions), autofocus: 'end', editable: true, injectCSS: true, @@ -182,61 +187,6 @@ function editorJsonToText(json: JSONContent): string { return text } -function textToEditorJson(text: string): JSONContent { - if (text === '' || text.length === 0) { - return { - text: '', - } - } - - const lines = text.split('\n') - const docContent: JSONContent[] = [] - - for (const line of lines) { - if (line.trim() === '') { - continue // skip empty lines - } - - const paragraphContent: JSONContent[] = [] - let position = 0 - - while (position < line.length) { - if (line[position] === '@') { - // Handle mentions - let endPosition = position + 1 - while (endPosition < line.length && /\S/.test(line[endPosition])) { - endPosition++ - } - const mentionId = line.substring(position + 1, endPosition) - paragraphContent.push({ - type: 'mention', - attrs: {id: mentionId}, - }) - position = endPosition - } else { - // Handle regular text - let endPosition = line.indexOf('@', position) - if (endPosition === -1) endPosition = line.length - paragraphContent.push({ - type: 'text', - text: line.substring(position, endPosition), - }) - position = endPosition - } - } - - docContent.push({ - type: 'paragraph', - content: paragraphContent, - }) - } - - return { - type: 'doc', - content: docContent, - } -} - const styles = StyleSheet.create({ container: { flex: 1, diff --git a/src/view/com/composer/text-input/web/LinkDecorator.ts b/src/view/com/composer/text-input/web/LinkDecorator.ts index 531e8d5a06..19945de086 100644 --- a/src/view/com/composer/text-input/web/LinkDecorator.ts +++ b/src/view/com/composer/text-input/web/LinkDecorator.ts @@ -16,7 +16,6 @@ import {Mark} from '@tiptap/core' import {Plugin, PluginKey} from '@tiptap/pm/state' -import {findChildren} from '@tiptap/core' import {Node as ProsemirrorNode} from '@tiptap/pm/model' import {Decoration, DecorationSet} from '@tiptap/pm/view' import {isValidDomain} from 'lib/strings/url-helpers' @@ -36,20 +35,20 @@ export const LinkDecorator = Mark.create({ function getDecorations(doc: ProsemirrorNode) { const decorations: Decoration[] = [] - findChildren(doc, node => node.type.name === 'paragraph').forEach( - paragraphNode => { - const textContent = paragraphNode.node.textContent + doc.descendants((node, pos) => { + if (node.isText && node.text) { + const textContent = node.textContent // links iterateUris(textContent, (from, to) => { decorations.push( - Decoration.inline(paragraphNode.pos + from, paragraphNode.pos + to, { + Decoration.inline(pos + from, pos + to, { class: 'autolink', }), ) }) - }, - ) + } + }) return DecorationSet.create(doc, decorations) } diff --git a/yarn.lock b/yarn.lock index 2bd08edb9b..7533bb439b 100644 --- a/yarn.lock +++ b/yarn.lock @@ -4972,6 +4972,13 @@ resolved "https://registry.yarnpkg.com/@tiptap/extension-text/-/extension-text-2.1.6.tgz#23f36114ee164e3da2fd326145ac7b7f8bd34c56" integrity sha512-CqV0N6ngoXZFeJGlQ86FSZJ/0k7+BN3S6aSUcb5DRAKsSEv/Ga1LvSG24sHy+dwjTuj3EtRPJSVZTFcSB17ZSA== +"@tiptap/html@^2.1.11": + version "2.1.11" + resolved "https://registry.yarnpkg.com/@tiptap/html/-/html-2.1.11.tgz#998421b526f200d01c549f37eb8fae2a0d1f0ed6" + integrity sha512-VKmBb1c3YN9hZfBzkV+QERf3ZWBUHHxjv2/BOr/Dw6mbb6+0iA1nxO9vQYPUb+xAmlm0n8vWwc7YQ8rxBwTKWQ== + dependencies: + zeed-dom "^0.9.19" + "@tiptap/pm@^2.0.0-beta.220": version "2.1.6" resolved "https://registry.yarnpkg.com/@tiptap/pm/-/pm-2.1.6.tgz#4c196a7147fedd71316ef3413bb0e98d5c97726d" @@ -19227,6 +19234,13 @@ yocto-queue@^1.0.0: resolved "https://registry.yarnpkg.com/yocto-queue/-/yocto-queue-1.0.0.tgz#7f816433fb2cbc511ec8bf7d263c3b58a1a3c251" integrity sha512-9bnSc/HEW2uRy67wc+T8UwauLuPJVn28jb+GtJY16iiKWyvmYJRXVT4UamsAEGQfPohgr2q4Tq0sQbQlxTfi1g== +zeed-dom@^0.9.19: + version "0.9.26" + resolved "https://registry.yarnpkg.com/zeed-dom/-/zeed-dom-0.9.26.tgz#f0127d1024b34a1233a321bd6d0275b3ba998b30" + integrity sha512-HWjX8rA3Y/RI32zby3KIN1D+mgskce+She4K7kRyyx62OiVxJ5FnYm8vWq0YVAja3Tf2S1M0XAc6O2lRFcMgcQ== + dependencies: + css-what "^6.1.0" + zeego@^1.6.2: version "1.7.0" resolved "https://registry.yarnpkg.com/zeego/-/zeego-1.7.0.tgz#8034adb842199c4ccf21bcb19877800bff18606b"