fix: emoji replacement

This commit is contained in:
Anthony Fu 2022-12-27 21:42:58 +01:00
parent c19dd3ee0f
commit dc94d707b0
7 changed files with 40 additions and 4 deletions

View file

@ -296,7 +296,7 @@ defineExpose({
<button <button
btn-action-icon btn-action-icon
:aria-label="$t('tooltip.toggle_code_block')" :aria-label="$t('tooltip.toggle_code_block')"
:class="editor.isActive('codeBlock') ? 'op100' : 'op50'" :class="editor.isActive('codeBlock') ? 'text-primary' : ''"
@click="editor?.chain().focus().toggleCodeBlock().run()" @click="editor?.chain().focus().toggleCodeBlock().run()"
> >
<div i-ri:code-s-slash-line /> <div i-ri:code-s-slash-line />

View file

@ -2,8 +2,9 @@
import type { Emoji } from 'masto' import type { Emoji } from 'masto'
import type { Node } from 'ultrahtml' import type { Node } from 'ultrahtml'
import { TEXT_NODE, parse, render, walkSync } from 'ultrahtml' import { TEXT_NODE, parse, render, walkSync } from 'ultrahtml'
import createEmojiRegex from 'emoji-regex'
export const EMOJI_REGEX = /(\p{Emoji_Presentation})/ug export const EMOJI_REGEX = createEmojiRegex()
const decoder = process.client ? document.createElement('textarea') : null as any as HTMLTextAreaElement const decoder = process.client ? document.createElement('textarea') : null as any as HTMLTextAreaElement
export function decodeHtml(text: string) { export function decodeHtml(text: string) {
@ -25,7 +26,7 @@ export function parseMastodonHTML(html: string, customEmojis: Record<string, Emo
? `<img src="${emoji.url}" alt=":${name}:" class="custom-emoji" data-emoji-id="${name}" />` ? `<img src="${emoji.url}" alt=":${name}:" class="custom-emoji" data-emoji-id="${name}" />`
: `:${name}:` : `:${name}:`
}) })
.replace(EMOJI_REGEX, '<em-emoji native="$1" />') .replace(EMOJI_REGEX, '<em-emoji native="$&" fallback="$&" />')
if (markdown) { if (markdown) {
// handle code blocks // handle code blocks

View file

@ -24,6 +24,9 @@ export const Emoji = Node.create({
native: { native: {
default: null, default: null,
}, },
fallback: {
default: null,
},
} }
}, },
@ -38,6 +41,7 @@ export const Emoji = Node.create({
type: this.name, type: this.name,
attrs: { attrs: {
native: name, native: name,
fallback: name,
}, },
}) })
}, },
@ -51,7 +55,10 @@ export const Emoji = Node.create({
type: this.type, type: this.type,
getAttributes: (match) => { getAttributes: (match) => {
const [native] = match const [native] = match
return { native } return {
native,
fallback: native,
}
}, },
}), }),
] ]

View file

@ -82,6 +82,7 @@
"@vueuse/nuxt": "^9.9.0", "@vueuse/nuxt": "^9.9.0",
"bumpp": "^8.2.1", "bumpp": "^8.2.1",
"emoji-mart": "^5.4.0", "emoji-mart": "^5.4.0",
"emoji-regex": "^10.2.1",
"eslint": "^8.30.0", "eslint": "^8.30.0",
"esno": "^0.16.3", "esno": "^0.16.3",
"file-saver": "^2.0.5", "file-saver": "^2.0.5",

View file

@ -38,6 +38,7 @@ specifiers:
browser-fs-access: ^0.31.1 browser-fs-access: ^0.31.1
bumpp: ^8.2.1 bumpp: ^8.2.1
emoji-mart: ^5.4.0 emoji-mart: ^5.4.0
emoji-regex: ^10.2.1
eslint: ^8.30.0 eslint: ^8.30.0
esno: ^0.16.3 esno: ^0.16.3
file-saver: ^2.0.5 file-saver: ^2.0.5
@ -136,6 +137,7 @@ devDependencies:
'@vueuse/nuxt': 9.9.0_nuxt@3.0.0 '@vueuse/nuxt': 9.9.0_nuxt@3.0.0
bumpp: 8.2.1 bumpp: 8.2.1
emoji-mart: 5.4.0 emoji-mart: 5.4.0
emoji-regex: 10.2.1
eslint: 8.30.0 eslint: 8.30.0
esno: 0.16.3 esno: 0.16.3
file-saver: 2.0.5 file-saver: 2.0.5
@ -4845,6 +4847,10 @@ packages:
resolution: {integrity: sha512-xrRrUmMqZG64oRxmUZcf8zSMUGQtIUYUL3aZD5iMkqAve+I9wMNh3OVOXL7NW9fEm48L2LI3BUPpj/DUIAJrVg==} resolution: {integrity: sha512-xrRrUmMqZG64oRxmUZcf8zSMUGQtIUYUL3aZD5iMkqAve+I9wMNh3OVOXL7NW9fEm48L2LI3BUPpj/DUIAJrVg==}
dev: true dev: true
/emoji-regex/10.2.1:
resolution: {integrity: sha512-97g6QgOk8zlDRdgq1WxwgTMgEWGVAQvB5Fdpgc1MkNy56la5SKP9GsMXKDOdqwn90/41a8yPwIGk1Y6WVbeMQA==}
dev: true
/emoji-regex/8.0.0: /emoji-regex/8.0.0:
resolution: {integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==} resolution: {integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==}
dev: true dev: true

View file

@ -54,6 +54,21 @@ exports[`html-parse > custom emoji > html 1`] = `
exports[`html-parse > custom emoji > text 1`] = `"Daniel Roe :nuxt:"`; exports[`html-parse > custom emoji > text 1`] = `"Daniel Roe :nuxt:"`;
exports[`html-parse > emojis > html 1`] = `
"🇫🇷 👨<em-emoji native=\\"\\" fallback=\\"\\"></em-emoji>👩<em-emoji
native=\\"\\"
fallback=\\"\\"
></em-emoji
>👦 👩<em-emoji native=\\"\\" fallback=\\"\\"></em-emoji>🚒🧑🏽<em-emoji
native=\\"\\"
fallback=\\"\\"
></em-emoji
>🚀
"
`;
exports[`html-parse > emojis > text 1`] = `"🇫🇷 👨‍👩‍👦 👩‍🚒🧑🏽‍🚀"`;
exports[`html-parse > empty > html 1`] = `""`; exports[`html-parse > empty > html 1`] = `""`;
exports[`html-parse > empty > text 1`] = `""`; exports[`html-parse > empty > text 1`] = `""`;

View file

@ -34,6 +34,12 @@ describe('html-parse', () => {
expect(serializedText).toMatchSnapshot('text') expect(serializedText).toMatchSnapshot('text')
}) })
it('emojis', async () => {
const { formatted, serializedText } = await render('🇫🇷 👨‍👩‍👦 👩‍🚒🧑🏽‍🚀')
expect(formatted).toMatchSnapshot('html')
expect(serializedText).toMatchSnapshot('text')
})
it('code frame', async () => { it('code frame', async () => {
// https://mas.to/@antfu/109396489827394721 // https://mas.to/@antfu/109396489827394721
const { formatted, serializedText } = await render('<p>Testing code block</p><p>```ts<br />import { useMouse, usePreferredDark } from &#39;@vueuse/core&#39;</p><p>// tracks mouse position<br />const { x, y } = useMouse()</p><p>// is the user prefers dark theme<br />const isDark = usePreferredDark()<br />```</p>') const { formatted, serializedText } = await render('<p>Testing code block</p><p>```ts<br />import { useMouse, usePreferredDark } from &#39;@vueuse/core&#39;</p><p>// tracks mouse position<br />const { x, y } = useMouse()</p><p>// is the user prefers dark theme<br />const isDark = usePreferredDark()<br />```</p>')