Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
34 changes: 34 additions & 0 deletions packages/webkit/src/components/feedback/toast/toast.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -219,6 +219,40 @@ describe('Toast (composition + imperative store)', () => {

expect(within(region!).queryByTestId('feedback-toast__close')).toBeNull()
})

it('honours a per-toast closable over a Toaster that closes nothing', async () => {
// Source: `item.entry.closable ?? closable` — the per-toast option wins.
// It only can if the region's projection of the store entry carries
// `closable`; when it did not, this option was silently inert.
await mountToaster({ position: 'bottom-right', duration: 0, closable: false })

toast.error('Deployment failed', { closable: true })
const region = await regionFor('bottom-right')
const scope = within(region!)

expect(scope.getByText('Deployment failed')).toBeTruthy()
expect(scope.getByTestId('feedback-toast__close')).toBeTruthy()
})

it('keeps a per-toast closable through an in-place update', async () => {
// The async pattern: a `loading` toast is raised first and only becomes
// closable when it settles into its error state under the SAME id.
await mountToaster({ position: 'bottom-right', duration: 0, closable: false })

const id = toast.loading('Deploying…')
let region = await regionFor('bottom-right')
expect(within(region!).queryByTestId('feedback-toast__close')).toBeNull()

useToastStore().update(id, {
type: 'error',
message: 'Deployment failed',
duration: 0,
closable: true
})
region = await regionFor('bottom-right')

expect(within(region!).getByTestId('feedback-toast__close')).toBeTruthy()
})
})

describe('per-toast position overrides the Toaster default', () => {
Expand Down
8 changes: 7 additions & 1 deletion packages/webkit/src/components/feedback/toast/toaster.vue
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,11 @@
if (changed) heights.value = nextHeights
}

// This projection IS the entry the region renders (`item.entry` below), not
// just a change-detection key — so every field the template or the default
// slot reads has to be carried here. `closable` in particular: without it the
// per-toast override is dropped and every toast falls back to the Toaster's
// prop. (`onClose` is deliberately absent: the store owns invoking it.)
watch(
() =>
store.toasts.map((t) => ({
Expand All @@ -127,7 +132,8 @@
description: t.description,
action: t.action,
duration: t.duration,
position: t.position
position: t.position,
closable: t.closable
})),
(next) => {
const nextIds = new Set(next.map((t) => t.id))
Expand Down
Loading