From 6c69017e5cc1a244ff206ee3bedc06d9192359ef Mon Sep 17 00:00:00 2001 From: InteraktivPreuss <108800743+InteraktivPreuss@users.noreply.github.com> Date: Wed, 10 Jun 2026 16:14:18 +0200 Subject: [PATCH 1/2] Document the toast framework and mount the region in cmsui/publicui - Add docs/how-to-guides/show-toasts.md and link it from the toctree - Mount the global Toast region in the cmsui and publicui layouts so toasts triggered from editor and visitor-facing routes actually render - Include Toast.css in both CSS bundles via the new layout/styles/cmsui.css and the updated layout/styles/publicui.css - Add success/info/error variants in Toast.css using Quanta tokens - Add an auto-dismiss countdown bar with prefers-reduced-motion support and region-level pause on hover or focus-within - Expose showProgress on ToastItem and a dismiss utility; show() now returns the toast key and accepts per-call timeout/onClose - Lower DEFAULT_TOAST_TIMEOUT_MS from 25 s to 6 s and normalize timeout<=0 - Add Storybook stories for the new variants and the showProgress flag - Add per-package news entries Refs #32. --- docs/how-to-guides/index.md | 1 + docs/how-to-guides/show-toasts.md | 185 ++++++++++++++++++ packages/cmsui/news/+toast-region.feature | 1 + packages/cmsui/routes/layout.tsx | 5 + .../components/news/+toast-variants.feature | 1 + .../components/src/styles/basic/Toast.css | 59 +++++- .../layout/components/Toast/Toast.stories.tsx | 172 ++++++++++++++-- packages/layout/components/Toast/Toast.tsx | 11 ++ packages/layout/config/toast.ts | 38 +++- packages/layout/news/+toast-framework.feature | 1 + packages/layout/styles/cmsui.css | 1 + packages/layout/styles/publicui.css | 1 + packages/publicui/news/+toast-region.feature | 1 + packages/publicui/routes/index.tsx | 4 + 14 files changed, 449 insertions(+), 32 deletions(-) create mode 100644 docs/how-to-guides/show-toasts.md create mode 100644 packages/cmsui/news/+toast-region.feature create mode 100644 packages/components/news/+toast-variants.feature create mode 100644 packages/layout/news/+toast-framework.feature create mode 100644 packages/layout/styles/cmsui.css create mode 100644 packages/publicui/news/+toast-region.feature diff --git a/docs/how-to-guides/index.md b/docs/how-to-guides/index.md index b42b76e4c..a171fdbc8 100644 --- a/docs/how-to-guides/index.md +++ b/docs/how-to-guides/index.md @@ -20,6 +20,7 @@ extend-vite-configuration access-registry register-and-retrieve-components register-and-retrieve-utilities +show-toasts configure-style-fields register-slots customize-login-screen diff --git a/docs/how-to-guides/show-toasts.md b/docs/how-to-guides/show-toasts.md new file mode 100644 index 000000000..ce5ca69da --- /dev/null +++ b/docs/how-to-guides/show-toasts.md @@ -0,0 +1,185 @@ +--- +myst: + html_meta: + "description": "How to show toast notifications in Plone Aurora using the @plone/layout toast framework." + "property=og:description": "How to show toast notifications in Plone Aurora using the @plone/layout toast framework." + "property=og:title": "Show toast notifications" + "keywords": "Plone Aurora, Plone, toast, notification, react-aria-components, @plone/layout" +--- + +# Show toast notifications + +Plone Aurora ships a global toast framework based on the `UNSTABLE_Toast` primitives from `react-aria-components`. +It is registered by `@plone/layout` and reachable from anywhere in the app via `@plone/registry`. +Use it to confirm successful actions, surface route errors, or report background-task progress. + + +## How the framework is wired + +`@plone/layout/config/toast.ts` exports a module-level `ToastQueue` and an `install()` function. +The queue wraps state updates in `document.startViewTransition` when the browser supports it, falling back to a plain update otherwise, so enter/exit animations stay in sync with React. +`install()` registers three utilities on `@plone/registry`: + +- `{ type: 'toast', name: 'queue' }` returns the queue itself (useful when you need to subscribe or render your own region). +- `{ type: 'toast', name: 'show' }` adds a `ToastItem` to the queue and returns its key. +- `{ type: 'toast', name: 'dismiss' }` closes the toast identified by a key returned from `show`. + +The visual `` region is `@plone/layout/components/Toast/Toast.tsx`. +It is mounted once per layout, next to `` / ``, so toasts appear regardless of which route the user is on. +The shared CSS lives in `@plone/components/styles/basic/Toast.css`. +It defines: + +- The region anchor (`.react-aria-ToastRegion`) and base toast container (`.react-aria-Toast`). +- Four visual variants picked up from the toast's `className`: the default (Quanta `denim`), `.success` (`turtle`), `.info` (`royal`), and `.error` (`wine`). All colors reference Quanta tokens with hex fallbacks so the styles render correctly outside a Quanta theme. +- The countdown bar (`.react-aria-Toast-progress`) rendered along the bottom edge of every timed toast. + + +## Show a toast + +```ts +import config from '@plone/registry'; + +config.getUtility({ type: 'toast', name: 'show' }).method({ + title: 'Saved', + description: 'Your changes have been saved.', +}); +``` + +The fields on `ToastItem` are: + +`title` +: Required. + Announced first by screen readers. + +`description` +: Optional supporting copy rendered below the title. + +`icon` +: Optional leading `ReactNode` rendered before the title. + +`className` +: Optional modifier class. + Pass `'success'`, `'info'`, or `'error'` to use one of the variants that ship in `Toast.css`. + Project add-ons can register their own classes for additional severities. + +`showProgress` +: Whether to render the auto-dismiss countdown bar at the bottom of the toast. + Defaults to `true`. + Pass `false` for short confirmations where the bar adds visual noise. + Ignored for sticky toasts (`timeout: null`), which never render a bar because there is no countdown to draw. + + +## Customize the timeout + +`show` accepts an options object as a second argument: + +```ts +config.getUtility({ type: 'toast', name: 'show' }).method( + { title: 'Uploading…', description: 'Hold on.' }, + { timeout: 8000 }, +); +``` + +`timeout` +: Auto-dismiss after `n` milliseconds. + Defaults to `DEFAULT_TOAST_TIMEOUT_MS` (currently 6 seconds), exported from `@plone/layout/config/toast`. + Pass `null` to require manual dismissal — useful for long-running operations that resolve via {ref}`dismiss `. + react-aria-components recommends a minimum of 5 seconds so screen-reader users have time to read the announcement. + +`onClose` +: Fires when the toast is removed for any reason (auto-dismiss, close button, programmatic dismiss). + + +## Countdown bar + +Every timed toast renders a thin progress bar pinned to its bottom edge. +The bar shrinks from full width to empty over the toast's `timeout`, giving the user a visual cue for how long the toast will remain on screen. + +Behavior: + +- Drawn as a single absolutely-positioned `
` inside the toast, clipped to the toast's rounded corners. +- Color is a lightening overlay (`rgba(255, 255, 255, 0.35)`) so it works against every variant background without per-variant styling. +- **Pauses on hover or focus**, mirroring react-aria's own pause-timers behavior. +- Never renders for sticky toasts (`timeout: null`) or when the caller sets `showProgress: false` on the item. +- Marked `aria-hidden` — it is decorative, not announced. + + +(show-toasts-dismiss)= + +## Dismiss a toast programmatically + +`show` returns an opaque `ToastKey`. +Pass it to the `dismiss` utility to remove the toast from code: + +```ts +import config from '@plone/registry'; + +const show = config.getUtility({ type: 'toast', name: 'show' }).method; +const dismiss = config.getUtility({ type: 'toast', name: 'dismiss' }).method; + +const key = show( + { title: 'Uploading…' }, + { timeout: null }, +); + +// later, when the upload finishes: +dismiss(key); +``` + + +## Surface route errors + +`@plone/layout` exposes an `ErrorToast` helper for React Router error boundaries. +It reads the route error and pushes a styled toast. + +```tsx +import config from '@plone/registry'; +import ErrorToast from '@plone/layout/components/Toast/ErrorToast'; + +export function ErrorBoundary() { + const queue = config.getUtility({ type: 'toast', name: 'queue' }).method(); + return ErrorToast(queue); +} +``` + + +## Render your own region + +The default `` region covers the common case (bottom-center, dismissable, view-transition animations). +If you need a different layout — for example a side-panel region or a region scoped to a specific route — render `UNSTABLE_ToastRegion` directly and pass the shared queue: + +```tsx +import { + UNSTABLE_Toast as Toast, + UNSTABLE_ToastContent as ToastContent, + UNSTABLE_ToastRegion as ToastRegion, +} from 'react-aria-components'; +import config from '@plone/registry'; + +function MyCustomRegion() { + const queue = config.getUtility({ type: 'toast', name: 'queue' }).method(); + return ( + + {({ toast }) => ( + + {/* … */} + + )} + + ); +} +``` + +Multiple regions can share the same queue. +Each rendered region receives every queued toast, so use them carefully — typically one global region per layout is enough. + + +## Where toasts appear today + +The region is mounted in: + +- `packages/cmsui/routes/layout.tsx` — every editor route +- `packages/publicui/routes/index.tsx` — every visitor-facing page +- `packages/contents/routes/layout.tsx` — the `/contents` UI + +`@plone/layout` is installed by `@plone/aurora`, so the queue and utilities are available in any package that depends on it. diff --git a/packages/cmsui/news/+toast-region.feature b/packages/cmsui/news/+toast-region.feature new file mode 100644 index 000000000..34f6fb8be --- /dev/null +++ b/packages/cmsui/news/+toast-region.feature @@ -0,0 +1 @@ +Mounted the global toast region in the cmsui layout so toasts triggered from editor routes render. @InteraktivPreuss diff --git a/packages/cmsui/routes/layout.tsx b/packages/cmsui/routes/layout.tsx index 49e3791d5..9f88eea67 100644 --- a/packages/cmsui/routes/layout.tsx +++ b/packages/cmsui/routes/layout.tsx @@ -18,7 +18,9 @@ import i18next from '@plone/aurora/app/i18next.server'; import type { RootLoader } from '@plone/aurora/app/root'; import { PluggablesProvider } from '@plone/layout/components/Pluggable'; import Toolbar from '@plone/layout/components/Toolbar/Toolbar'; +import Toast from '@plone/layout/components/Toast/Toast'; import { shouldShowToolbar } from '@plone/layout/helpers'; +import config from '@plone/registry'; import stylesheet from '@plone/aurora/.plone/cmsui.css?url'; import { ploneContentContext } from '@plone/aurora/app/middleware.server'; @@ -105,6 +107,9 @@ export default function Index() {
+ diff --git a/packages/components/news/+toast-variants.feature b/packages/components/news/+toast-variants.feature new file mode 100644 index 000000000..39f3a0c96 --- /dev/null +++ b/packages/components/news/+toast-variants.feature @@ -0,0 +1 @@ +Added `success`, `info`, and `error` variants and an auto-dismiss countdown bar to `Toast.css`, and switched its hardcoded hex values to Quanta tokens with fallbacks. @InteraktivPreuss diff --git a/packages/components/src/styles/basic/Toast.css b/packages/components/src/styles/basic/Toast.css index 157f65c30..1ef6af838 100644 --- a/packages/components/src/styles/basic/Toast.css +++ b/packages/components/src/styles/basic/Toast.css @@ -1,6 +1,6 @@ .react-aria-ToastRegion { - --toast-bg: #021322; - --toast-fg: #fff; + --toast-bg: var(--color-quanta-denim, #021322); + --toast-fg: var(--color-quanta-air, #fff); position: fixed; @@ -23,22 +23,32 @@ .react-aria-Toast { &.error { - --toast-bg: #6d030a; + --toast-bg: var(--color-quanta-wine, #a91c09); } + &.success { + --toast-bg: var(--color-quanta-turtle, #256619); + } + + &.info { + --toast-bg: var(--color-quanta-royal, #085696); + } + + position: relative; display: flex; + overflow: hidden; align-items: center; padding: 0.8rem 1rem; border-radius: 6px; background: var(--toast-bg); - box-shadow: 0px 2px 4px 0px #f0f1f2; + box-shadow: 0px 2px 4px 0px var(--color-quanta-snow, #f3f5f7); color: var(--toast-fg); gap: 16px; outline: none; &[data-focus-visible] { - outline: 2px solid var(--toast-bg); - outline-offset: 2px; + outline: 2px solid var(--toast-fg); + outline-offset: -2px; } .react-aria-ToastContent { @@ -72,13 +82,44 @@ outline: none; &[data-focus-visible] { - box-shadow: - 0 0 0 2px var(--toast-bg), - 0 0 0 4px var(--toast-fg); + outline: 2px solid var(--toast-fg); + outline-offset: -2px; } &[data-pressed] { background: rgba(255, 255, 255, 0.2); } } + + .react-aria-Toast-progress { + position: absolute; + bottom: 0; + left: 0; + width: 100%; + height: 3px; + animation: react-aria-Toast-progress var(--toast-duration, 6000ms) linear + forwards; + background: rgba(255, 255, 255, 0.35); + transform-origin: left center; + } +} + +.react-aria-ToastRegion:hover .react-aria-Toast-progress, +.react-aria-ToastRegion:focus-within .react-aria-Toast-progress { + animation-play-state: paused; +} + +@media (prefers-reduced-motion: reduce) { + .react-aria-Toast-progress { + animation: none; + } +} + +@keyframes react-aria-Toast-progress { + from { + transform: scaleX(1); + } + to { + transform: scaleX(0); + } } diff --git a/packages/layout/components/Toast/Toast.stories.tsx b/packages/layout/components/Toast/Toast.stories.tsx index ec6dfd7ff..d1f3d940c 100644 --- a/packages/layout/components/Toast/Toast.stories.tsx +++ b/packages/layout/components/Toast/Toast.stories.tsx @@ -1,39 +1,181 @@ +import { useState } from 'react'; import Toast from './Toast'; import config from '@plone/registry'; +import { CheckboxIcon, InfoIcon, CloseIcon } from '@plone/components/Icons'; +import type { ToastKey } from '../../config/toast'; import type { Meta, StoryObj } from '@storybook/react-vite'; +const queue = () => + config.getUtility({ name: 'queue', type: 'toast' }).method(); +const show = () => config.getUtility({ name: 'show', type: 'toast' }).method; +const dismiss = () => + config.getUtility({ name: 'dismiss', type: 'toast' }).method; + const meta = { title: 'Toast', component: Toast, tags: ['autodocs'], + parameters: { + docs: { + description: { + component: + 'Bottom-center region for `react-aria-components` toasts. Queue and `show` helper are registered in `@plone/layout/config/toast.ts`.', + }, + }, + }, } satisfies Meta; export default meta; type Story = StoryObj; +/** Minimal usage via the `show` utility. */ export const Default: Story = { - args: { - queue: config - .getUtility({ - name: 'queue', - type: 'toast', - }) - .method(), - }, + args: { queue: queue() }, render: (args: any) => ( <> ), }; + +/** Variant picked by `className` on the toast item. */ +export const Variants: Story = { + args: { queue: queue() }, + render: (args: any) => ( + <> +
+ + + +
+ + + ), +}; + +/** Suppress the countdown bar via `showProgress: false`. */ +export const WithoutProgressBar: Story = { + args: { queue: queue() }, + render: (args: any) => ( + <> + + + + ), +}; + +/** `timeout: null` keeps the toast on screen until the user dismisses it. */ +export const Persistent: Story = { + args: { queue: queue() }, + render: (args: any) => ( + <> + + + + ), +}; + +/** `show()` returns a key; pass it to `dismiss(key)`. */ +export const ProgrammaticDismiss: Story = { + args: { queue: queue() }, + render: function Render(args: any) { + const [key, setKey] = useState(null); + return ( + <> +
+ + +
+ + + ); + }, +}; diff --git a/packages/layout/components/Toast/Toast.tsx b/packages/layout/components/Toast/Toast.tsx index a766e134b..d949d3c6c 100644 --- a/packages/layout/components/Toast/Toast.tsx +++ b/packages/layout/components/Toast/Toast.tsx @@ -40,6 +40,17 @@ const AppToast = (props: AppToastPropsType) => { + {toast.timeout && toast.content.showProgress !== false ? ( + + From f51f3e6780ef1315cc73a6a06e9ce68f817aa550 Mon Sep 17 00:00:00 2001 From: InteraktivPreuss <108800743+InteraktivPreuss@users.noreply.github.com> Date: Thu, 11 Jun 2026 10:39:59 +0200 Subject: [PATCH 2/2] Split the toast docs into how-to and concept guides MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Following review feedback on #118, separate the explanation content from task-oriented guidance per Diátaxis: - Add docs/conceptual-guides/toasts.md covering the architecture (queue, registry utilities, region, and CSS), the countdown bar behavior, and where the region is mounted. Link it from the conceptual-guides toctree. - Trim docs/how-to-guides/show-toasts.md to show, customize timeout, dismiss, surface route errors, and render your own region. Add a cross-reference to the new concept page at the top. Apply the inline rewrites in their final files: {file} role for file paths, definition lists for the registry utilities and mount points, "React Aria" terminology, one-sentence-per-line phrasing, and the Storybook demo link near the top of both pages. Backtick cmsui and publicui in the three news entries. --- docs/conceptual-guides/index.md | 1 + docs/conceptual-guides/toasts.md | 87 +++++++++++++++++++ docs/how-to-guides/show-toasts.md | 72 ++++----------- packages/cmsui/news/+toast-region.feature | 2 +- packages/layout/news/+toast-framework.feature | 2 +- packages/publicui/news/+toast-region.feature | 2 +- 6 files changed, 107 insertions(+), 59 deletions(-) create mode 100644 docs/conceptual-guides/toasts.md diff --git a/docs/conceptual-guides/index.md b/docs/conceptual-guides/index.md index 1fcd52731..5cbb0d7ae 100644 --- a/docs/conceptual-guides/index.md +++ b/docs/conceptual-guides/index.md @@ -24,4 +24,5 @@ add-on-driven-configuration cookieplone-frontend-add-on routing slots +toasts ``` diff --git a/docs/conceptual-guides/toasts.md b/docs/conceptual-guides/toasts.md new file mode 100644 index 000000000..1cb6b9ce7 --- /dev/null +++ b/docs/conceptual-guides/toasts.md @@ -0,0 +1,87 @@ +--- +myst: + html_meta: + "description": "An explanation of the toast notification framework in Plone Aurora, including its architecture, visual variants, and the countdown bar." + "property=og:description": "An explanation of the toast notification framework in Plone Aurora, including its architecture, visual variants, and the countdown bar." + "property=og:title": "Toast notifications" + "keywords": "Plone Aurora, Plone, toast, notification, React Aria, @plone/layout" +--- + +# Toast notifications + +Plone Aurora ships a global toast framework based on the `UNSTABLE_Toast` primitives from React Aria Components. +It is registered by `@plone/layout` and reachable from anywhere in the app via `@plone/registry`, so add-ons can confirm successful actions, surface route errors, or report background task progress without each one having to mount its own region. + +See a [demo of toasts](https://plone-storybook.readthedocs.io/?path=/docs/layout_toast--docs). + +For task-oriented guidance, see {doc}`../how-to-guides/show-toasts`. + + +## Architecture + +The framework has three layers: a single shared queue, three registry utilities that wrap it, and a visual region that subscribes to the queue and renders each toast. + + +### The queue and registry utilities + +In the package `@plone/layout`, its file {file}`packages/layout/config/toast.ts` exports a module-level `ToastQueue` and an `install()` function. + +The queue wraps state updates with the function `document.startViewTransition` when the browser supports it, falling back to a plain update otherwise. +Enter and exit animations stay in sync with React. + +The `install()` function registers three utilities in `@plone/registry` for working with toasts: + +`{ type: 'toast', name: 'queue' }` +: Returns the queue itself. + This is useful to subscribe or render a custom region. + +`{ type: 'toast', name: 'show' }` +: Adds a `ToastItem` to the queue and returns its key. + +`{ type: 'toast', name: 'dismiss' }` +: Closes the toast identified by a key returned from `show`. + + +### The region and CSS + +The visual `` region is defined in {file}`packages/layout/components/Toast/Toast.tsx`. +It's mounted once per layout, so toasts appear regardless of which route the user is on. + +The shared CSS lives in {file}`components/src/styles/basic/Toast.css`. +It defines: + +- The region anchor (`.react-aria-ToastRegion`) and base toast container (`.react-aria-Toast`). +- Four visual variants picked up from the toast's `className`: the default (Quanta `denim`), `.success` (`turtle`), `.info` (`royal`), and `.error` (`wine`). + All colors reference Quanta tokens with hexadecimal fallbacks, so the styles render correctly outside a Quanta theme. +- The countdown bar (`.react-aria-Toast-progress`) rendered along the bottom edge of every timed toast. + + +## Countdown bar + +Every timed toast renders a thin progress bar pinned to its bottom edge. +The bar shrinks from full width to empty over the toast's `timeout` duration, giving the user a visual cue for how long the toast will remain on screen. + +A toast appears and behaves as described below. + +- Drawn as a single absolutely-positioned `
` inside the toast, clipped to the toast's rounded corners. +- Background color is a lightening overlay, implemented with (`rgba(255, 255, 255, 0.35)`). + It works against every variant background without per-variant styling. +- Pauses on hover or focus, mirroring React Aria's own pause-timers behavior. +- Never renders for sticky toasts, either declared with `timeout: null` or when the caller sets `showProgress: false` on the item. +- Marked `aria-hidden`, because it's decorative, not announced. + + +## Where toasts appear today + +The region is mounted in the following files. + +{file}`packages/cmsui/routes/layout.tsx` +: every editor route + +{file}`packages/publicui/routes/index.tsx` +: every visitor-facing page + +{file}`packages/contents/routes/layout.tsx` +: the `/contents` UI + +`@plone/layout` is installed by `@plone/aurora`, so the queue and utilities are available in any package that depends on it. diff --git a/docs/how-to-guides/show-toasts.md b/docs/how-to-guides/show-toasts.md index ce5ca69da..332f9f416 100644 --- a/docs/how-to-guides/show-toasts.md +++ b/docs/how-to-guides/show-toasts.md @@ -4,34 +4,18 @@ myst: "description": "How to show toast notifications in Plone Aurora using the @plone/layout toast framework." "property=og:description": "How to show toast notifications in Plone Aurora using the @plone/layout toast framework." "property=og:title": "Show toast notifications" - "keywords": "Plone Aurora, Plone, toast, notification, react-aria-components, @plone/layout" + "keywords": "Plone Aurora, Plone, toast, notification, React Aria, @plone/layout" --- # Show toast notifications -Plone Aurora ships a global toast framework based on the `UNSTABLE_Toast` primitives from `react-aria-components`. +Plone Aurora ships a global toast framework based on the `UNSTABLE_Toast` primitives from React Aria Components. It is registered by `@plone/layout` and reachable from anywhere in the app via `@plone/registry`. -Use it to confirm successful actions, surface route errors, or report background-task progress. +Use it to confirm successful actions, surface route errors, or report background task progress. +See a [demo of toasts](https://plone-storybook.readthedocs.io/?path=/docs/layout_toast--docs). -## How the framework is wired - -`@plone/layout/config/toast.ts` exports a module-level `ToastQueue` and an `install()` function. -The queue wraps state updates in `document.startViewTransition` when the browser supports it, falling back to a plain update otherwise, so enter/exit animations stay in sync with React. -`install()` registers three utilities on `@plone/registry`: - -- `{ type: 'toast', name: 'queue' }` returns the queue itself (useful when you need to subscribe or render your own region). -- `{ type: 'toast', name: 'show' }` adds a `ToastItem` to the queue and returns its key. -- `{ type: 'toast', name: 'dismiss' }` closes the toast identified by a key returned from `show`. - -The visual `` region is `@plone/layout/components/Toast/Toast.tsx`. -It is mounted once per layout, next to `` / ``, so toasts appear regardless of which route the user is on. -The shared CSS lives in `@plone/components/styles/basic/Toast.css`. -It defines: - -- The region anchor (`.react-aria-ToastRegion`) and base toast container (`.react-aria-Toast`). -- Four visual variants picked up from the toast's `className`: the default (Quanta `denim`), `.success` (`turtle`), `.info` (`royal`), and `.error` (`wine`). All colors reference Quanta tokens with hex fallbacks so the styles render correctly outside a Quanta theme. -- The countdown bar (`.react-aria-Toast-progress`) rendered along the bottom edge of every timed toast. +For an explanation of how the framework is wired and where the region is mounted, see {doc}`../conceptual-guides/toasts`. ## Show a toast @@ -59,8 +43,8 @@ The fields on `ToastItem` are: `className` : Optional modifier class. - Pass `'success'`, `'info'`, or `'error'` to use one of the variants that ship in `Toast.css`. - Project add-ons can register their own classes for additional severities. + Pass `'success'`, `'info'`, or `'error'` to use one of the variants that ship in {file}`Toast.css`. + Project add-ons can register their own classes for additional toast alert styles. `showProgress` : Whether to render the auto-dismiss countdown bar at the bottom of the toast. @@ -81,27 +65,13 @@ config.getUtility({ type: 'toast', name: 'show' }).method( ``` `timeout` -: Auto-dismiss after `n` milliseconds. - Defaults to `DEFAULT_TOAST_TIMEOUT_MS` (currently 6 seconds), exported from `@plone/layout/config/toast`. - Pass `null` to require manual dismissal — useful for long-running operations that resolve via {ref}`dismiss `. - react-aria-components recommends a minimum of 5 seconds so screen-reader users have time to read the announcement. +: An integer representing the duration in milliseconds after which a toast will be auto-dismissed. + Defaults to the value set by `DEFAULT_TOAST_TIMEOUT_MS`, currently 6000 milliseconds, exported from {file}`layout/config/toast.ts`. + Pass `null` to require manual dismissal, which is useful for long-running operations that resolve via {ref}`dismiss `. + React Aria recommends a minimum of 5 seconds, so people who use a screen reader have time to read the announcement. `onClose` -: Fires when the toast is removed for any reason (auto-dismiss, close button, programmatic dismiss). - - -## Countdown bar - -Every timed toast renders a thin progress bar pinned to its bottom edge. -The bar shrinks from full width to empty over the toast's `timeout`, giving the user a visual cue for how long the toast will remain on screen. - -Behavior: - -- Drawn as a single absolutely-positioned `
` inside the toast, clipped to the toast's rounded corners. -- Color is a lightening overlay (`rgba(255, 255, 255, 0.35)`) so it works against every variant background without per-variant styling. -- **Pauses on hover or focus**, mirroring react-aria's own pause-timers behavior. -- Never renders for sticky toasts (`timeout: null`) or when the caller sets `showProgress: false` on the item. -- Marked `aria-hidden` — it is decorative, not announced. +: Fires when the toast is removed for any reason, including auto-dismiss, close button, and programmatic dismiss. (show-toasts-dismiss)= @@ -145,8 +115,8 @@ export function ErrorBoundary() { ## Render your own region -The default `` region covers the common case (bottom-center, dismissable, view-transition animations). -If you need a different layout — for example a side-panel region or a region scoped to a specific route — render `UNSTABLE_ToastRegion` directly and pass the shared queue: +The default `` region covers the common case, including bottom-center, dismissable, and view-transition animations. +For a different layout—for example, a side-panel region or a region scoped to a specific route—render `UNSTABLE_ToastRegion` directly, and pass the shared queue: ```tsx import { @@ -171,15 +141,5 @@ function MyCustomRegion() { ``` Multiple regions can share the same queue. -Each rendered region receives every queued toast, so use them carefully — typically one global region per layout is enough. - - -## Where toasts appear today - -The region is mounted in: - -- `packages/cmsui/routes/layout.tsx` — every editor route -- `packages/publicui/routes/index.tsx` — every visitor-facing page -- `packages/contents/routes/layout.tsx` — the `/contents` UI - -`@plone/layout` is installed by `@plone/aurora`, so the queue and utilities are available in any package that depends on it. +Each rendered region receives every queued toast, so use them carefully. +Typically, one global region per layout is enough. diff --git a/packages/cmsui/news/+toast-region.feature b/packages/cmsui/news/+toast-region.feature index 34f6fb8be..2f1c7e4b4 100644 --- a/packages/cmsui/news/+toast-region.feature +++ b/packages/cmsui/news/+toast-region.feature @@ -1 +1 @@ -Mounted the global toast region in the cmsui layout so toasts triggered from editor routes render. @InteraktivPreuss +Mounted the global toast region in the `cmsui` layout, so toasts triggered from editor routes render. @InteraktivPreuss diff --git a/packages/layout/news/+toast-framework.feature b/packages/layout/news/+toast-framework.feature index f17ed8d8b..4a665b7e1 100644 --- a/packages/layout/news/+toast-framework.feature +++ b/packages/layout/news/+toast-framework.feature @@ -1 +1 @@ -Added `showProgress` and `dismiss` to the toast framework, made the `show` utility return the toast key and accept a per-call `timeout`/`onClose`, lowered the default timeout to 6 seconds, and wired `Toast.css` into both the publicui and cmsui style bundles. @InteraktivPreuss +Added `showProgress` and `dismiss` to the toast framework, made the `show` utility return the toast key and accept a per-call `timeout`/`onClose`, lowered the default timeout to 6 seconds, and wired `Toast.css` into both the `publicui` and `cmsui` style bundles. @InteraktivPreuss diff --git a/packages/publicui/news/+toast-region.feature b/packages/publicui/news/+toast-region.feature index 782ab2638..59fc8faed 100644 --- a/packages/publicui/news/+toast-region.feature +++ b/packages/publicui/news/+toast-region.feature @@ -1 +1 @@ -Mounted the global toast region in the publicui layout so toasts triggered from visitor-facing routes render. @InteraktivPreuss +Mounted the global toast region in the `publicui` layout so toasts triggered from visitor-facing routes render. @InteraktivPreuss