# Toast Notifications

Kanoa MES can show toast notifications on any Perspective page: short messages that slide in at the edge of the screen and close on their own. Toasts are powered by [react-toastify](https://fkhadra.github.io/react-toastify/) and are shown from scripts using the [`system.kanoa.toast`](../systemFunctions/apiToastIntro.md) functions. Nothing needs to be placed on a view. Every Perspective page in every project can show toasts as soon as the module is installed.

```python
system.kanoa.toast.show({"message": "Lot 123 released", "type": "success"})
```

Up to 25 toasts are shown on a page at once. Any beyond that wait until space frees up.

## Script Functions

| Function | Description |
| --- | --- |
| [system.kanoa.toast.show](../systemFunctions/toast/show.md) | Shows a toast and returns its id. |
| [system.kanoa.toast.update](../systemFunctions/toast/update.md) | Changes a toast that is still on screen. |
| [system.kanoa.toast.dismiss](../systemFunctions/toast/dismiss.md) | Closes one toast, or every toast on the page. |

### Default Values

Any key you leave out of the dictionary uses these defaults.

| Key | Default |
| --- | --- |
| `message` | None. Required for `show`. |
| `title` | None. No heading is shown. |
| `type` | `default` |
| `position` | `bottom-center` |
| `animate` | `bounce` |
| `autoClose` | `5000` (5 seconds) |
| `closeButton` | `True` |
| `pauseOnHover` | `True` |
| `draggable` | Swipe to dismiss on touch screens only. Pass `True` to allow dragging with a mouse as well. |
| `loading` | `False` |
| `id` | A generated UUID, returned by `show`. |
| `sessionId` | The session the calling Perspective script is running on. Required from Gateway scripts. |
| `pageId` | The page the calling Perspective script is running on. Required from Gateway scripts. |

### Which Page Shows the Toast

- **From a Perspective script** (a component event, view script, message handler or session event), the toast goes to the page the script is running on. `sessionId` and `pageId` are not needed.
- **From a Gateway script** (a tag change script, timer, WebDev endpoint, or any code run through `system.util.invokeAsynchronous`), there is no current page, so pass both `sessionId` and `pageId`. This works the same way as `system.perspective.sendMessage`.
- **From the Designer Script Console**, the functions raise an error. They are Perspective-only.

Invalid arguments (an unknown `type`, text over the length limit, a missing `message`) raise an error in the calling script rather than being silently ignored.

### Loading Toasts

For work that takes a moment, show a loading toast first and then update it with the result. A loading toast shows a spinner, has no close button and stays open until you update it.

```python
import time
toastId = system.kanoa.toast.show({"message": "Releasing lot 123...", "loading": True})
try:
    releaseLot(123)
    time.sleep(3)
    system.kanoa.toast.update({"id": toastId, "message": "Lot 123 released", "type": "success"})
except:
    system.kanoa.toast.update({"id": toastId, "message": "Release failed", "type": "error"})
    raise
```

Updating a loading toast without `"loading": True` stops the spinner and gives it back its close button and auto-close timer. To change the message while keeping the spinner (for example, to show progress), pass `"loading": True` again. To make sure a loading toast cannot stay open forever if a script fails, give it an `autoClose` when you show it.

If the work runs in the background with `system.util.invokeAsynchronous`, read the session and page ids before starting, and pass them to `update`:

```python
sessionId, pageId = self.session.props.id, self.page.props.pageId
toastId = system.kanoa.toast.show({"message": "Working...", "loading": True})

def work():
    # ... long task ...
    system.kanoa.toast.update({"id": toastId, "message": "Done", "type": "success",
                               "sessionId": sessionId, "pageId": pageId})

system.util.invokeAsynchronous(work)
```

### Text Is Always Plain Text

The message and title are displayed exactly as written. HTML tags appear as literal text and are never interpreted, so it is safe to show values that came from users, tags or the database.

## Component Events

Toasts report their lifecycle to the view that showed them. These events are added to every Perspective container, but only fire on a view's **root container**. They appear in the root container's event configuration in the Designer.

For a toast shown from a Perspective script, the event fires on the root container of the view the script is running in. For a toast shown from a Gateway script, it fires on the page's primary view. Each toast fires one `onToastOpen` and one `onToastClose`. Nothing fires if the view has already closed.

### onToastOpen

Triggered when a toast shown by this view opens.

| Property | Type | Description |
| --- | --- | --- |
| event.id | string | The toast's id, as returned by `system.kanoa.toast.show`. |

### onToastClose

Triggered when a toast shown by this view closes, whether it timed out, was dismissed by a script, or was closed by the user.

| Property | Type | Description |
| --- | --- | --- |
| event.id | string | The toast's id, as returned by `system.kanoa.toast.show`. |
| event.removedByUser | boolean | `true` when the user closed the toast (close button, click or swipe). |

## Styling Toasts

### Default: Toasts Follow the Perspective Theme

With no setup, toasts take their colors, font, corner radius and shadow from the session's Perspective theme:

- The background and text use the theme's `--containerRoot` and `--label`.
- `info`, `success`, `warning` and `error` toasts use the theme's `--info`, `--success`, `--warning` and `--error`.
- The progress bar and loading spinner use `--callToAction`.

Switching themes (for example, setting `session.props.theme` to `kanoa-dark`) restyles toasts that are already on screen. Custom themes built on Perspective's standard variables get matching toasts automatically.

A theme counts as dark when `dark` is one of the hyphen-separated words in its name (`dark`, `dark-cool`, `kanoa-dark`, ...).

### Overriding Colors and Sizes

To change how toasts look, set any of these CSS variables. Each one falls back to the Perspective theme variable shown, and then to a fixed value if the theme does not define that.

| Variable | Controls | Default |
| --- | --- | --- |
| `--kanoa-toast-background` | Toast background | `--containerRoot` |
| `--kanoa-toast-text` | Message and title text | `--label` |
| `--kanoa-toast-info` | `info` toast accent and icon | `--info` |
| `--kanoa-toast-success` | `success` toast accent and icon | `--success` |
| `--kanoa-toast-warning` | `warning` toast accent and icon | `--warning` |
| `--kanoa-toast-error` | `error` toast accent and icon | `--error` |
| `--kanoa-toast-progress` | Auto-close progress bar | `--callToAction` |
| `--kanoa-toast-spinner` | Loading spinner | `--callToAction` |
| `--kanoa-toast-spinner-track` | Loading spinner's empty track | `--neutral-30` |
| `--kanoa-toast-font-family` | Font | `--font-NotoSans` |
| `--kanoa-toast-border-radius` | Corner radius | `--borderRadius` |
| `--kanoa-toast-shadow` | Drop shadow | `--boxShadow3` |
| `--kanoa-toast-width` | Toast width | `320px` |
| `--kanoa-toast-z-index` | Stacking order | `14015` |

Set them on `:root`:

```css
:root {
  --kanoa-toast-background: #1E2A38;
  --kanoa-toast-text: #F4F4F4;
  --kanoa-toast-success: #2ECC71;
  --kanoa-toast-font-family: "Inter", sans-serif;
}
```

Set the `--kanoa-toast-*` variables, not react-toastify's own `--toastify-*` variables. The `--toastify-*` variables are set by the module and overriding them is not reliable.

### Where to Put Your Overrides

- **In a Perspective theme file**, to apply to every project that uses that theme. Perspective loads only the active theme's CSS, so you can give each theme its own toast colors: put dark values in your dark theme and light values in your light theme.
- **In a project's advanced stylesheet**, to apply to one project whatever its theme.

### Styling Beyond Colors

For borders, layout or typography, target these class names. Start each selector with `#kanoa-toast-root` so it takes priority over the built-in styles without `!important`.

| Class | Element |
| --- | --- |
| `.Toastify__toast` | Every toast |
| `.Toastify__toast--info`, `--success`, `--warning`, `--error`, `--default` | Toasts of that type |
| `.Toastify__toast-theme--light`, `.Toastify__toast-theme--dark` | Toasts on a light or dark theme |
| `.kanoa-toast__title` | The title |
| `.kanoa-toast__message` | The message |
| `.Toastify__progress-bar` | The auto-close progress bar |
| `.Toastify__close-button` | The close button |

```css
#kanoa-toast-root .Toastify__toast--error {
  border-left: 4px solid var(--error);
}

#kanoa-toast-root .kanoa-toast__title {
  text-transform: uppercase;
}
```

### Layering

Toasts appear above docked views, Perspective's connection and notification banners, tooltips and modal popups, and below the Perspective app bar. To change this, set `--kanoa-toast-z-index`.
