feat(web): align attachment display with DeepSeek Chat via ui-attachment atoms
Single-click original preview in the composer rail and chat history; remove control inside the thumbnail, revealed on hover/focus (always on touch); hidden-scrollbar rail overflow paged by edge arrows with wheel panning and end-reveal on add; image-intake rejections and prompt failures announce as a transient top-center toast instead of inline strips. The attachment atoms move to a new zero-cordis package @deepseek-ai/dsh-client-ui-attachment (rail, message gallery, lightbox), seeded as a platform module; the toast is a ui-primitives atom. Strings arrive as label props bridged from the conversation dictionary.
This commit is contained in:
40
packages/client/ui-primitives/tests/toast.spec.tsx
Normal file
40
packages/client/ui-primitives/tests/toast.spec.tsx
Normal file
@@ -0,0 +1,40 @@
|
||||
// @vitest-environment jsdom
|
||||
|
||||
import { afterEach, describe, expect, it, vi } from 'vitest'
|
||||
import { cleanup, render } from '@testing-library/react'
|
||||
import { Toast } from '../src/Toast.tsx'
|
||||
|
||||
afterEach(cleanup)
|
||||
|
||||
describe('Toast', () => {
|
||||
it('announces its text and reports done after the hold-and-fade lifetime', () => {
|
||||
vi.useFakeTimers()
|
||||
try {
|
||||
const onDone = vi.fn()
|
||||
const view = render(<Toast text="最多添加 50 张图片" icon={<svg data-testid="icon" />} onDone={onDone} />)
|
||||
const banner = view.getByRole('alert')
|
||||
expect(banner.textContent).toContain('最多添加 50 张图片')
|
||||
expect(view.getByTestId('icon')).toBeTruthy()
|
||||
vi.advanceTimersByTime(3999)
|
||||
expect(onDone).not.toHaveBeenCalled()
|
||||
vi.advanceTimersByTime(1)
|
||||
expect(onDone).toHaveBeenCalledTimes(1)
|
||||
} finally {
|
||||
vi.useRealTimers()
|
||||
}
|
||||
})
|
||||
|
||||
it('renders without an icon and cancels its timer on unmount', () => {
|
||||
vi.useFakeTimers()
|
||||
try {
|
||||
const onDone = vi.fn()
|
||||
const view = render(<Toast text="plain" onDone={onDone} />)
|
||||
expect(view.getByRole('alert').querySelector('[aria-hidden]')).toBeNull()
|
||||
view.unmount()
|
||||
vi.advanceTimersByTime(10_000)
|
||||
expect(onDone).not.toHaveBeenCalled()
|
||||
} finally {
|
||||
vi.useRealTimers()
|
||||
}
|
||||
})
|
||||
})
|
||||
Reference in New Issue
Block a user