You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
This repository was archived by the owner on Nov 4, 2026. It is now read-only.
Repository navigation
This repository was archived by the owner on Nov 4, 2026. It is now read-only.
Notification displayType is honored in the contract but every type still presents as a toast #3014
Follow-up from #2942 / PR #3008, which closed the contract half of this and deliberately left the presentation half open. Recording it so it doesn't get lost.
NotificationContext used to store displayType on the item and never read it, under a union that claimed alignment with NotificationTypeSchema while carrying a renderer-local modal and missing alert / inline. That is now correct:
the union matches the spec enum (toast | snackbar | banner | alert | inline), with modal kept as a deprecated legacy spelling that presents as alert;
notify() materializes the declared type (spec default toast), so a consumer can branch on it;
positions match NotificationPositionSchema (underscores), hyphens kept for stored items;
a parity guard fails if either vocabulary drifts.
What is still open
Nothing distinguishes the five types at render time.NotificationProvider delegates every notification to the host's onToast callback regardless of displayType, so a banner and an inline notification both surface as a toast. The value is no longer inert — it reaches the delegate — but no delegate acts on it.
Concretely, packages/react/src/context/NotificationContext.tsx calls onToast(notification) for every item. The console's handler (useConsoleActionRuntime) routes that to sonner.
What "done" would look like
Each spec type gets a presentation that is actually distinct:
bottom-anchored transient with an optional single action
banner
persistent, page-width strip at the top of the content area
alert
modal-ish blocking acknowledgement
inline
rendered in place by the surface that raised it, not floating
Open questions worth settling before implementing:
Who owns banner/inline placement? They are not overlays — a banner needs a slot in the app shell's content area, and inline needs the raising surface to render it. That likely means the context exposes the items and the shell/surface subscribes, rather than a single onToast-style delegate.
Is alert a modal? If so it should probably route through the existing ModalHandler rather than growing a second modal path.
Does snackbar earn a distinct component, or is it a sonner variant? If the latter, say so in the spec's describe() rather than implying a separate surface.
Why it is worth doing
An author picking banner gets a toast — the output is plausible and wrong, which is the #2901 Tier 1 shape rather than Tier 2. It did not rank as Tier 1 in the audit only because displayType was inert at the time (nothing read it at all), so the audit filed it under "silently absent". Now that the contract is live, the mismatch is a wrong-presentation bug.
Activity
feat(notifications): each spec displayType gets its own presentation (#…
feat(app-shell): the console mounts the notification surfaces (#3014 …
fix(notifications): the spec `icon` is read instead of stored and ign…
fix(notifications): the config, position and action variant are read …