[6.x] Wrangle toast messages - #19746
brianjhanson wants to merge 9 commits into
Conversation
Chips set `show-thumb` and emitted a thumbnail slot for every Thumbable element, even when it had no thumbnail. Since the slot got a fixed size, that showed up as a blank square. Only render the slot when there's something to put in it; the reload settings still carry `showThumb`. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Flash::success()/error()/notice() now add `{id, type, message, settings,
target}` to a single `cp-messages` session list on control panel
requests (site requests keep the plain session keys). The Inertia
`messages` prop and the Twig `cpMessages()` function both read it via
Flash::all(), which also picks up messages flashed straight to the plain
keys. The old `flash` prop is kept but deprecated.
JSON responses from asSuccess()/asFailure() return their message in a
`messages` list (with the id also in `notificationSettings`) instead of
flashing it, so it can't reappear on a later page. asFailure() now keeps
its summary message when there are validation errors.
Controllers that used `->with('success'|'error')` now use Flash, and
FieldsController no longer flashes an error before a JSON validation
failure. Adds the `assertMessage()` test response macro.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
`resources/js/modules/messages` is the one path every control panel message takes: server-flashed messages (Inertia `messages` prop, or `window.CraftMessageQueue` on Twig pages), JSON responses (`showMessagesFromResponse()`), the `craft-message` window event, and legacy `Craft.cp.display*()` calls through a shim. `showMessage()` drops repeats by id (remembered in sessionStorage), sends targeted messages to inline outlets, and shows the rest in the default display. The container is a new `<cp-messages>` element rendered by both the Twig layout and `app.blade.php`. It builds two live regions up front (`role="alert"` for errors, `role="status"` otherwise) and holds the user's position preference in a `position` attribute, which Inertia responses keep current. `Craft.CP.Notification` still draws each message, now as a Sonner-style stack: collapsed behind the newest, spread out on hover, press or focus, at most five visible. Messages close after the user's notification duration, except errors and ones with actions. Timers pause while the stack is expanded or the tab is hidden. Adds swipe to dismiss, a <craft-button> close button, reduced-motion support, a "Skip to messages" skip link, and room for the Laravel Debugbar via the existing `--cp-debug-bar-height`. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Replaces the FlashMessages banner, useFlash() and the global useFlashMessages() store (which leaked messages across pages and hid client messages behind server ones) with useMessages(). The 30 client calls now go through the shared queue, and the duplicate announce watcher in PageScreen is gone. InlineFlash becomes a named outlet: messages targeting it render beside the control that caused them, with their own live regions, and fall back to the default display when it isn't on the page. The email test and Find and Replace use it; the page Save button no longer repeats the page-level message. The login form shows OAuth errors targeted at `login` inline instead of as a message. TransitionFade respects reduced motion. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Adds docs/messages.md: how messages travel, sending them from PHP controllers, Flash, Vue and JavaScript, inline outlets, what plugins should use (PHP, the Yii adapter, Craft.cp and the `craft-message` event), the default display and its accessibility, setup, and tuning. Replaces the module README, and adds changelog entries. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…messages # Conflicts: # packages/craftcms-legacy/cp/src/js/CP.js # resources/js/modules/settings/composables/useSettingsSave.ts # src/Cp/Html/ElementHtml.php # src/Http/RespondsWithFlash.php
Renames `--messages-*` to `--cp-messages-*` and the per-message `--message-index`/`--message-offset` to `--cp-message-*`, matching the CP's other custom properties, and updates the documented defaults. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
📚 Storybook previews@craftcms/ui — open Storybook No changed components detected in this Storybook. resources/js — open Storybook No changed components detected in this Storybook. |
…messages # Conflicts: # CHANGELOG.md # resources/js/modules/elements/composables/useElementIndexPage.ts
|
This PR had conflicts with Claude's response
|
…messages # Conflicts: # CHANGELOG.md
|
This PR had conflicts with Claude's response
|
The control panel had four separate ways of telling someone that something worked or failed: the legacy corner stack, a banner at the top of the page, text beside the Save button, and a client-side store. None of them knew about the others. Messages showed up twice, got lost between pages, or reappeared on unrelated pages, and screen reader support varied depending on which one you hit.
This PR replaces them with one queue and one display. Every message, whether it comes from a PHP controller, a JSON response, Vue, legacy JavaScript or a plugin, takes the same path, looks the same, and is shown once.
It's worth noting that this is ideally not the final state of these things. Toasts are generally not great and not recommended by accessibility experts. For the moment, I thought it was better to restore things to roughly how they worked in v5 vs. rethinking everything right now. With the plumbing in place, we should be able to adjust the UI down the line. I'm thinking we'll use the
settingsavailable on each message as a way to tell the system how to display the message (inline,banner,toast, etc.).📖 Full documentation: docs/messages.md covers usage for core and plugins, inline messages, the display, accessibility and tuning.
What changes
Upgrade notes
See the docs for details and examples.
Also included