fix(chat): animate inserted Markdown lists and code lines
This commit is contained in:
parent
3d74f52344
commit
608cbc9960
|
|
@ -7,6 +7,14 @@
|
|||
|
||||
.chat-markdown {
|
||||
--shiki-dark-bg: var(--color-input);
|
||||
|
||||
&[data-chat-markdown-mode='streaming'] {
|
||||
[data-stream-markdown='li'],
|
||||
[data-stream-markdown='code-block'],
|
||||
[data-stream-markdown='code-line'] {
|
||||
@apply animate-in fade-in duration-200 motion-reduce:animate-none;
|
||||
}
|
||||
}
|
||||
@apply text-[11px] leading-4;
|
||||
|
||||
[data-stream-markdown='blockquote'],
|
||||
|
|
|
|||
64
tests/e2e/chat/streaming-animation.spec.ts
Normal file
64
tests/e2e/chat/streaming-animation.spec.ts
Normal file
|
|
@ -0,0 +1,64 @@
|
|||
import { expect, test } from '@playwright/test'
|
||||
|
||||
import { CanvasHelper } from '#tests/helpers/canvas'
|
||||
|
||||
test('streaming lists and code lines animate only when inserted', async ({ page }) => {
|
||||
await page.goto('/?test')
|
||||
await new CanvasHelper(page).waitForInit()
|
||||
const fixture = await page.evaluateHandle(async () => {
|
||||
const vuePath = '/node_modules/.vite/deps/vue.js'
|
||||
const markdownPath = '/src/components/chat/ChatMarkdown.vue'
|
||||
const { createApp, h, ref, nextTick } = await import(vuePath)
|
||||
const { default: ChatMarkdown } = await import(markdownPath)
|
||||
const content = ref('A paragraph.\n\n- First item\n')
|
||||
const mode = ref('streaming')
|
||||
const host = document.createElement('div')
|
||||
host.dataset.slot = 'streaming-animation-fixture'
|
||||
document.body.append(host)
|
||||
const app = createApp(() => h(ChatMarkdown, { content: content.value, mode: mode.value }))
|
||||
app.mount(host)
|
||||
return {
|
||||
async append(text: string) {
|
||||
content.value += text
|
||||
await nextTick()
|
||||
},
|
||||
async settle() {
|
||||
mode.value = 'static'
|
||||
await nextTick()
|
||||
},
|
||||
dispose() {
|
||||
app.unmount()
|
||||
host.remove()
|
||||
}
|
||||
}
|
||||
})
|
||||
try {
|
||||
const markdown = page.locator('[data-slot="streaming-animation-fixture"]')
|
||||
const first = markdown.locator('[data-stream-markdown="li"]').first()
|
||||
await expect(first).toHaveCSS('animation-name', 'enter')
|
||||
await fixture.evaluate((state) =>
|
||||
state.append('\n- Second item\n\n```typescript\nconst a = 1\n')
|
||||
)
|
||||
await expect(markdown.locator('[data-stream-markdown="li"]')).toHaveCount(2)
|
||||
const code = markdown.locator('[data-stream-markdown="code-block"]')
|
||||
await expect(code).toBeVisible()
|
||||
await expect(code).toHaveCSS('animation-name', 'enter')
|
||||
const line = markdown.locator('[data-stream-markdown="code-line"]').first()
|
||||
await expect(line).toHaveCSS('animation-name', 'enter')
|
||||
await fixture.evaluate((state) => state.append('const b = 2\n```'))
|
||||
await expect(code).toContainText('const b = 2')
|
||||
await page.emulateMedia({ reducedMotion: 'reduce' })
|
||||
await expect(first).toHaveCSS('animation-name', 'none')
|
||||
await expect(line).toHaveCSS('animation-name', 'none')
|
||||
await fixture.evaluate((state) => state.settle())
|
||||
await page.emulateMedia({ reducedMotion: 'no-preference' })
|
||||
await expect(first).toHaveCSS('animation-name', 'none')
|
||||
await expect(markdown.locator('[data-stream-markdown="code-block"]')).toHaveCSS(
|
||||
'animation-name',
|
||||
'none'
|
||||
)
|
||||
} finally {
|
||||
await fixture.evaluate((state) => state.dispose())
|
||||
await fixture.dispose()
|
||||
}
|
||||
})
|
||||
Loading…
Reference in a new issue