feat(content-rich html parsing): add paragraphs LTR/RTL direction support (#2545)

This commit is contained in:
Joaquín Sánchez 2024-03-05 07:25:58 +01:00 committed by GitHub
parent 6cbe65c9d8
commit 3120bbb77f
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
4 changed files with 188 additions and 15 deletions

View file

@ -524,10 +524,21 @@ function transformMarkdown(node: Node) {
return _markdownProcess(node.value) return _markdownProcess(node.value)
} }
function addBdiParagraphs(node: Node) {
if (node.name === 'p' && !('dir' in node.attributes) && node.children?.length && node.children.length > 1)
node.attributes.dir = 'auto'
return node
}
function transformParagraphs(node: Node): Node | Node[] { function transformParagraphs(node: Node): Node | Node[] {
// Add bdi to paragraphs
addBdiParagraphs(node)
// For top level paragraphs, inject an empty <p> to preserve status paragraphs in our editor (except for the last one) // For top level paragraphs, inject an empty <p> to preserve status paragraphs in our editor (except for the last one)
if (node.parent?.type === DOCUMENT_NODE && node.name === 'p' && node.parent.children.at(-1) !== node) if (node.parent?.type === DOCUMENT_NODE && node.name === 'p' && node.parent.children.at(-1) !== node)
return [node, h('p')] return [node, h('p')]
return node return node
} }

View file

@ -38,7 +38,7 @@ const isDark = usePreferredDark()</pre></p>"
`; `;
exports[`content-rich > code frame 2 1`] = ` exports[`content-rich > code frame 2 1`] = `
"<p> "<p dir="auto">
<span class="h-card" <span class="h-card"
><a ><a
class="u-url mention" class="u-url mention"
@ -53,12 +53,12 @@ exports[`content-rich > code frame 2 1`] = `
" "
`; `;
exports[`content-rich > code frame empty 1`] = `"<p><pre class="code-block"></pre><br></p>"`; exports[`content-rich > code frame empty 1`] = `"<p dir="auto"><pre class="code-block"></pre><br></p>"`;
exports[`content-rich > code frame no lang 1`] = `"<p><pre class="code-block">hello world</pre><br>no lang</p>"`; exports[`content-rich > code frame no lang 1`] = `"<p dir="auto"><pre class="code-block">hello world</pre><br>no lang</p>"`;
exports[`content-rich > collapse mentions 1`] = ` exports[`content-rich > collapse mentions 1`] = `
"<p> "<p dir="auto">
<span class="h-card" <span class="h-card"
><a ><a
class="u-url mention" class="u-url mention"
@ -167,7 +167,7 @@ exports[`content-rich > handles formatting from servers 1`] = `
`; `;
exports[`content-rich > handles html within code blocks 1`] = ` exports[`content-rich > handles html within code blocks 1`] = `
"<p> "<p dir="auto">
HTML block code:<br /> HTML block code:<br />
<pre class="code-block"> <pre class="code-block">
&lt;span class=&quot;icon--noto icon--noto--1st-place-medal&quot;&gt;&lt;/span&gt; &lt;span class=&quot;icon--noto icon--noto--1st-place-medal&quot;&gt;&lt;/span&gt;
@ -178,7 +178,7 @@ exports[`content-rich > handles html within code blocks 1`] = `
`; `;
exports[`content-rich > hashtag adds bdi 1`] = ` exports[`content-rich > hashtag adds bdi 1`] = `
"<p> "<p dir="auto">
Testing bdi is added Testing bdi is added
<span <span
><VMenu ><VMenu
@ -199,7 +199,7 @@ exports[`content-rich > hashtag adds bdi 1`] = `
`; `;
exports[`content-rich > hashtag doesn't add 2 bdi 1`] = ` exports[`content-rich > hashtag doesn't add 2 bdi 1`] = `
"<p> "<p dir="auto">
Testing bdi not added Testing bdi not added
<span <span
><VMenu ><VMenu
@ -218,12 +218,12 @@ exports[`content-rich > hashtag doesn't add 2 bdi 1`] = `
`; `;
exports[`content-rich > hides collapsed mentions 1`] = ` exports[`content-rich > hides collapsed mentions 1`] = `
"<p>content</p> "<p dir="auto">content</p>
" "
`; `;
exports[`content-rich > inline code with link 1`] = ` exports[`content-rich > inline code with link 1`] = `
"<p> "<p dir="auto">
Inline code with link: Inline code with link:
<code <code
>https://api.iconify.design/noto.css?icons=1st-place-medal,2nd-place-medal</code >https://api.iconify.design/noto.css?icons=1st-place-medal,2nd-place-medal</code
@ -233,7 +233,7 @@ exports[`content-rich > inline code with link 1`] = `
`; `;
exports[`content-rich > link + mention 1`] = ` exports[`content-rich > link + mention 1`] = `
"<p> "<p dir="auto">
Happy Happy
<img <img
src="/emojis/twemoji/1f917.svg" src="/emojis/twemoji/1f917.svg"
@ -262,13 +262,161 @@ exports[`content-rich > link + mention 1`] = `
" "
`; `;
exports[`content-rich > p moved to div and text children replaced with p[dir="auto"] tags: br children removed 1`] = `
"<p dir="auto">
<span class="h-card"
><a
class="u-url mention"
rel="nofollow noopener noreferrer"
to="/strangeobject.space/@bebatjof"
><bdi>@<span>bebatjof</span></bdi></a
></span
>
هذا اختبار:<br />أنا أحب الطريقة التي يتم بها دعم النموذج المزدوج العربي. تمت
ترجمة الكلمة الأخيرة بشكل خاطئ وأحاول العثور على كيفية إصلاحها. أيضًا، يجب
إصلاح نموذج 0.
</p>
<p></p>
<p dir="auto">
This is a test:<br />I like how the arabic dual form is supported. The last
one is mistranslated and I&#39;m trying to find how to fix it. Also, the form
for 0 needs to be fixed.
</p>
<p></p>
"
`;
exports[`content-rich > plain text 1`] = ` exports[`content-rich > plain text 1`] = `
"hello there "hello there
" "
`; `;
exports[`content-rich > root p includes dir="auto" attr when mixed content 1`] = `
"<p dir="auto">
هذا اختبار جديد
<img
src="/emojis/twemoji/1f426.svg"
class="iconify-emoji iconify-emoji--twemoji"
alt="🐦"
/><img
src="/emojis/twemoji/1f424.svg"
class="iconify-emoji iconify-emoji--twemoji"
alt="🐤"
/>
<span class="h-card"
><a
class="u-url mention"
rel="nofollow noopener noreferrer"
to="/strangeobject.space/@bebatjof"
><bdi>@<span>bebatjof</span></bdi></a
></span
>
<br />أنا أحب الطريقة التي يتم بها دعم النموذج المزدوج العربي. تمت ترجمة
الكلمة الأخيرة بشكل خاطئ وأحاول العثور على كيفية إصلاحها.
<img
src="/emojis/twemoji/1f426.svg"
class="iconify-emoji iconify-emoji--twemoji"
alt="🐦"
/><img
src="/emojis/twemoji/1f424.svg"
class="iconify-emoji iconify-emoji--twemoji"
alt="🐤"
/>
;). كما أن النموذج الخاص بـ 0 يحتاج إلى إصلاح
<span
><VMenu
placement="bottom-start"
class="inline-block"
close-on-content-click="false"
><a
class="mention hashtag"
rel="nofollow noopener noreferrer"
to="/m.webtoo.ls/tags/turkey"
><bdi>#<span>turkey</span></bdi></a
></VMenu
></span
>
<span
><VMenu
placement="bottom-start"
class="inline-block"
close-on-content-click="false"
><a
class="mention hashtag"
rel="nofollow noopener noreferrer"
to="/m.webtoo.ls/tags/%D8%A7%D9%84%D8%B9%D8%B1%D8%A8%D9%8A%D8%A9"
><bdi>#<span>العربية</span></bdi></a
></VMenu
></span
>
.
</p>
<p></p>
<p dir="auto">
This is a new test
<img
src="/emojis/twemoji/1f426.svg"
class="iconify-emoji iconify-emoji--twemoji"
alt="🐦"
/><img
src="/emojis/twemoji/1f424.svg"
class="iconify-emoji iconify-emoji--twemoji"
alt="🐤"
/>
<span class="h-card"
><a
class="u-url mention"
rel="nofollow noopener noreferrer"
to="/strangeobject.space/@bebatjof"
><bdi>@<span>bebatjof</span></bdi></a
></span
>
<br />I like how the arabic dual form is supported. The last one is
mistranslated and I&#39;m trying to find how to fix it.
<img
src="/emojis/twemoji/1f426.svg"
class="iconify-emoji iconify-emoji--twemoji"
alt="🐦"
/><img
src="/emojis/twemoji/1f424.svg"
class="iconify-emoji iconify-emoji--twemoji"
alt="🐤"
/>
;). Also, the form for 0 needs to be fixed
<span
><VMenu
placement="bottom-start"
class="inline-block"
close-on-content-click="false"
><a
class="mention hashtag"
rel="nofollow noopener noreferrer"
to="/m.webtoo.ls/tags/turkey"
><bdi>#<span>turkey</span></bdi></a
></VMenu
></span
>
<span
><VMenu
placement="bottom-start"
class="inline-block"
close-on-content-click="false"
><a
class="mention hashtag"
rel="nofollow noopener noreferrer"
to="/m.webtoo.ls/tags/%D8%A7%D9%84%D8%B9%D8%B1%D8%A8%D9%8A%D8%A9"
><bdi>#<span>العربية</span></bdi></a
></VMenu
></span
>
.
</p>
<p></p>
"
`;
exports[`content-rich > shows some collapsed mentions grouped 1`] = ` exports[`content-rich > shows some collapsed mentions grouped 1`] = `
"<p> "<p dir="auto">
<mention-group <mention-group
><span class="h-card" ><span class="h-card"
><a ><a
@ -300,7 +448,7 @@ exports[`content-rich > shows some collapsed mentions grouped 1`] = `
`; `;
exports[`content-rich > shows some collapsed mentions inline 1`] = ` exports[`content-rich > shows some collapsed mentions inline 1`] = `
"<p> "<p dir="auto">
<span class="h-card" <span class="h-card"
><a ><a
class="u-url mention" class="u-url mention"

View file

@ -22,7 +22,7 @@ const isDark = usePreferredDark()
`; `;
exports[`html-parse > code frame 2 > html 1`] = ` exports[`html-parse > code frame 2 > html 1`] = `
"<p> "<p dir="auto">
<span class="h-card" <span class="h-card"
><a ><a
href="https://webtoo.ls/@antfu" href="https://webtoo.ls/@antfu"
@ -99,7 +99,7 @@ exports[`html-parse > html entities > html 1`] = `
exports[`html-parse > html entities > text 1`] = `"Hello <World />."`; exports[`html-parse > html entities > text 1`] = `"Hello <World />."`;
exports[`html-parse > inline markdown > html 1`] = `"<p>text <code>code</code> <b>bold</b> <em>italic</em> <del>del</del></p><p></p><p><pre><code class="language-js">code block</code></pre></p>"`; exports[`html-parse > inline markdown > html 1`] = `"<p dir="auto">text <code>code</code> <b>bold</b> <em>italic</em> <del>del</del></p><p></p><p><pre><code class="language-js">code block</code></pre></p>"`;
exports[`html-parse > inline markdown > text 1`] = ` exports[`html-parse > inline markdown > text 1`] = `
"text \`code\` **bold** *italic* ~~del~~ "text \`code\` **bold** *italic* ~~del~~
@ -111,7 +111,7 @@ code block
`; `;
exports[`html-parse > link + mention > html 1`] = ` exports[`html-parse > link + mention > html 1`] = `
"<p> "<p dir="auto">
Happy Happy
<img <img
src="/emojis/twemoji/1f917.svg" src="/emojis/twemoji/1f917.svg"

View file

@ -167,6 +167,20 @@ describe('content-rich', () => {
`) `)
expect(formatted).toMatchSnapshot() expect(formatted).toMatchSnapshot()
}) })
it ('root p includes dir="auto" attr when mixed content', async () => {
const { formatted } = await render(`
<p>هذا اختبار جديد 🐦🐤 <span class="h-card"><a href="https://strangeobject.space/@bebatjof" class="u-url mention">@<span>bebatjof</span></a></span> <br />أنا أحب الطريقة التي يتم بها دعم النموذج المزدوج العربي. تمت ترجمة الكلمة الأخيرة بشكل خاطئ وأحاول العثور على كيفية إصلاحها. 🐦🐤 ;). كما أن النموذج الخاص بـ 0 يحتاج إلى إصلاح <a href="https://m.webtoo.ls/tags/turkey" class="mention hashtag" rel="tag">#<span>turkey</span></a> <a href="https://m.webtoo.ls/tags/%D8%A7%D9%84%D8%B9%D8%B1%D8%A8%D9%8A%D8%A9" class="mention hashtag" rel="tag">#<span>العربية</span></a> .</p><p>This is a new test 🐦🐤 <span class="h-card"><a href="https://strangeobject.space/@bebatjof" class="u-url mention">@<span>bebatjof</span></a></span> <br />I like how the arabic dual form is supported. The last one is mistranslated and I&#39;m trying to find how to fix it. 🐦🐤 ;). Also, the form for 0 needs to be fixed <a href="https://m.webtoo.ls/tags/turkey" class="mention hashtag" rel="tag">#<span>turkey</span></a> <a href="https://m.webtoo.ls/tags/%D8%A7%D9%84%D8%B9%D8%B1%D8%A8%D9%8A%D8%A9" class="mention hashtag" rel="tag">#<span>العربية</span></a> .</p>
`)
expect(formatted).toMatchSnapshot()
})
it ('p moved to div and text children replaced with p[dir="auto"] tags: br children removed', async () => {
const { formatted } = await render(`
<p><span class="h-card"><a href="https://strangeobject.space/@bebatjof" class="u-url mention">@<span>bebatjof</span></a></span> هذا اختبار:<br />أنا أحب الطريقة التي يتم بها دعم النموذج المزدوج العربي. تمت ترجمة الكلمة الأخيرة بشكل خاطئ وأحاول العثور على كيفية إصلاحها. أيضًا، يجب إصلاح نموذج 0.</p><p>This is a test:<br />I like how the arabic dual form is supported. The last one is mistranslated and I&#39;m trying to find how to fix it. Also, the form for 0 needs to be fixed.</p>
`)
expect(formatted).toMatchSnapshot()
})
}) })
describe('editor', () => { describe('editor', () => {