PHPackages                             sugarcraft/sugar-toast - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [Utility &amp; Helpers](/categories/utility)
4. /
5. sugarcraft/sugar-toast

ActiveLibrary[Utility &amp; Helpers](/categories/utility)

sugarcraft/sugar-toast
======================

PHP port of DaltonSW/bubbleup — floating alert notification component for terminal UIs. Supports error/warning/info/success alerts at 6 screen positions, dynamic width, NerdFont/Unicode/ASCII symbols, auto-dismiss timers.

00PHP

Since Jun 1Pushed 1w agoCompare

[ Source](https://github.com/sugarcraft/sugar-toast)[ Packagist](https://packagist.org/packages/sugarcraft/sugar-toast)[ RSS](/packages/sugarcraft-sugar-toast/feed)WikiDiscussions master Synced 1w ago

READMEChangelogDependenciesVersions (1)Used By (0)

[![sugar-toast](.assets/icon.png)](.assets/icon.png)

[![CI](https://github.com/detain/sugarcraft/actions/workflows/ci.yml/badge.svg?branch=master)](https://github.com/detain/sugarcraft/actions/workflows/ci.yml)[![codecov](https://camo.githubusercontent.com/d6dbe8158d1677b80c9b5c9dde65b093587a4ac3f59c92d4ec0a3fae7e10167e/68747470733a2f2f636f6465636f762e696f2f67682f64657461696e2f737567617263726166742f6272616e63682f6d61737465722f67726170682f62616467652e7376673f666c61673d73756761722d746f617374)](https://app.codecov.io/gh/detain/sugarcraft?flags%5B0%5D=sugar-toast)[![Packagist Version](https://camo.githubusercontent.com/8bef8cd0b44cb5afc752ae1fc93e450a5221e1f35dee4c46768fb84fbee7d0c4/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f762f7375676172636f72652f73756761722d746f6173743f6c6162656c3d7061636b6167697374)](https://packagist.org/packages/sugarcore/sugar-toast)[![License](https://camo.githubusercontent.com/7013272bd27ece47364536a221edb554cd69683b68a46fc0ee96881174c4214c/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f6c6963656e73652d4d49542d626c75652e737667)](LICENSE)[![PHP](https://camo.githubusercontent.com/e78ffc83837c0d12647811a7fd1910c3cbeae04988de94bb4fd5b67e0874696a/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f7068702d254532253839254135382e312d3838393262662e737667)](https://www.php.net/)

SugarToast
==========

[](#sugartoast)

PHP port of [DaltonSW/bubbleup](https://github.com/daltonsw/bubbleup) — floating alert notification component for terminal UIs. Alerts float to the top of your TUI like bubbles in soda.

Features
--------

[](#features)

- **9 positions**: TopLeft, TopCenter, TopRight, MiddleLeft, MiddleCenter, MiddleRight, BottomLeft, BottomCenter, BottomRight
- **4 alert types**: Error, Warning, Info, Success — each with distinct styling
- **Dynamic width**: fixed or auto-sizing between minWidth and maxWidth
- **Symbol sets**: NerdFont (icons), Unicode (boxed), ASCII (plain text)
- **Auto-dismiss**: duration-based expiry support
- **Multiple alerts**: queue of toasts rendered in order
- **Progress toasts**: inline progress bar (0–100%) beneath the message body
- **Action buttons**: `[Label]` buttons attached to an alert with closure callbacks
- **History log**: immutable record of every dismissed alert
- **Fade animation stub**: `withAnimationDuration()` (CubicBezier deferred to future phase)
- **Pure renderer**: outputs ANSI strings; works with any TUI framework

Install
-------

[](#install)

```
composer require sugarcraft/sugar-toast
```

Quick Start
-----------

[](#quick-start)

```
use SugarCraft\Toast\{Position, Toast, ToastType};

$toast = Toast::new(50)  // max width 50
    ->withPosition(Position::TopRight)
    ->withDuration(10.0);  // seconds

// Add alerts
$toast = $toast->alert(ToastType::Success, 'File saved!');
$toast = $toast->alert(ToastType::Error, 'Connection failed');

// Render into a viewport
$bg = str_repeat("background content\n", 20);
echo $toast->View($bg);
```

Alert Types
-----------

[](#alert-types)

```
ToastType::Error
ToastType::Warning
ToastType::Info
ToastType::Success
```

Each type also provides a localized label via `ToastType::label()` (e.g. `ToastType::Success->label()` → `"Success"` in English).

`alert()` accepts either a `ToastType` enum case or a lowercase string (`"error"`, `"warning"`, `"info"`, `"success"`). Passing an unknown string throws `InvalidArgumentException`.

Positions
---------

[](#positions)

```
Position::TopLeft
Position::TopCenter
Position::TopRight
Position::MiddleLeft
Position::MiddleCenter
Position::MiddleRight
Position::BottomLeft
Position::BottomCenter
Position::BottomRight
```

Overflow &amp; Concurrency
--------------------------

[](#overflow--concurrency)

```
Overflow::DropOldest  // remove oldest alert to make room (default)
Overflow::DropNewest  // discard the new alert instead of enqueueing
Overflow::Enqueue     // allow queue to exceed maxConcurrent
```

Control the maximum number of concurrent alerts with `withMaxConcurrent(int|null)`:

- Pass an integer to cap the queue size
- Pass `null` for unlimited (default)

When the cap is reached, the configured `Overflow` strategy determines behaviour.

Persistent Alerts
-----------------

[](#persistent-alerts)

By default, alerts inherit `withDuration()` for auto-dismiss timing. Pass `null` as the `$expiresAt` argument to `alert()` to create a persistent alert that never expires automatically:

```
$toast = $toast->alert(ToastType::Info, 'Connected', null);  // never expires
```

Persistent alerts are dismissed only via `dismiss()`, `clear()`, or `pruneExpired()`.

Internationalization
--------------------

[](#internationalization)

User-facing strings are internationalized via `SugarCraft\Toast\Lang::t()`. All translatable strings live in `lang/en.php` under the `'toast'` namespace.

**Available keys** (`lang/en.php`):

KeyDefault stringParameters`type.info``Info`—`type.warning``Warning`—`type.error``Error`—`type.success``Success`—`dismiss``Press any key to dismiss`—`count``{count} notification(s)``{count}`To add a locale, copy `lang/en.php` to `lang/.php` and translate the values. The lookup chain follows `SugarCraft\Core\I18n\T`: exact locale → base language → `en` → raw key.

**Using the facade:**

```
use SugarCraft\Toast\Lang;
use SugarCraft\Toast\ToastType;

$label = ToastType::Error->label();        // 'Error' (i18n-aware)
$prompt = Lang::t('dismiss');            // 'Press any key to dismiss'
$counter = Lang::t('count', ['count' => 3]); // '3 notification(s)'
```

**Adding new translatable strings:**

```
// In any source file:
use SugarCraft\Toast\Lang;

// Simple key:
$msg = Lang::t('dismiss');

// With placeholder:
$counter = Lang::t('count', ['count' => $n]);
```

Progress Toasts
---------------

[](#progress-toasts)

Add a progress bar beneath the message body using `progressToast()`:

```
$toast = $toast->progressToast(ToastType::Info, 'Downloading...', 0.65);
// Re-render as progress updates:
$toast = $toast->progressToast(ToastType::Info, 'Downloading...', 0.80);
```

`progressToast()` accepts the same `$expiresAt` override as `alert()`. The progress value (0.0–1.0) is clamped automatically.

Action Buttons
--------------

[](#action-buttons)

Attach clickable buttons to an alert via `Alert::withActions()`:

```
use SugarCraft\Toast\{Action, Toast, ToastType};

$action = Action::make('Retry', function (): void {
    // reconnect logic here
});

$alert = (new Alert(ToastType::Error, 'Connection lost'))
    ->withActions([$action]);

$toast = $toast->alert(ToastType::Error, 'Connection lost')
    ->withActions([$action]);
```

`Action` is a value object with `readonly string $label` and `readonly \Closure(): void $callback`. When the action is triggered, invoke `$action->callback()` directly in your key/mouse handler.

History Log
-----------

[](#history-log)

`Toast` maintains an immutable history of every dismissed alert via `HistoryLog`:

```
// Dismiss all active alerts and record them
$toast = $toast->dismiss();

// Retrieve the log
$history = $toast->getHistory();  // list

foreach ($history as $alert) {
    echo $alert->type->label() . ': ' . $alert->message . "\n";
}
```

`HistoryLog` is immutable — `dismiss()` returns a new `Toast` with an updated log; prior instances are unchanged.

Animations
----------

[](#animations)

```
$toast = $toast->withAnimationDuration(0.25);
```

Set a fade animation duration in seconds. When &gt; 0, toasts render a character-reveal hint. Full CubicBezier spring easing (honey-bounce) is wired but deferred — the `animationDuration` field is a functional stub for now.

API Summary
-----------

[](#api-summary)

MethodDescription`Toast::new(int $maxWidth = 50)`Factory`->withPosition(Position)`Screen position (9 positions)`->withDuration(?float $seconds)`Auto-dismiss after N seconds; `null` disables`->withMaxWidth(int)`Maximum alert width in cells`->withMinWidth(int)`Minimum alert width in cells`->withSymbolSet(SymbolSet)`NerdFont, Unicode, or ASCII symbols`->withAllowEscToClose(bool)`Allow Escape key to dismiss`->withMaxConcurrent(?int $n)`Cap concurrent alerts (`null` = unlimited)`->withOverflow(Overflow)`Strategy when cap exceeded: DropOldest, DropNewest, Enqueue`->withAnimationDuration(float $seconds)`Fade animation duration (stub; CubicBezier deferred)`->alert(ToastType|string, string, ?float $expiresAt)`Add alert (string type = case-insensitive)`->progressToast(ToastType|string, string, float $progress, ?float $expiresAt)`Add alert with progress bar (0.0–1.0)`->error/warning/info/success(string)`Convenience alert helpers`->hasActiveAlert(): bool`True if non-expired alerts queued`->dismiss() / clear() / pruneExpired()`Manage alert lifecycle; `dismiss()` records to history`->getHistory(): list`Return all dismissed alerts`->view(string $background, int $w, int $h): string`Render toast layer over backgroundClassMethodDescription`Alert``withProgress(float)`Attach progress bar (0.0–1.0, clamped)`Alert``withActions(list)`Attach action buttons`Alert``isExpired(): bool`Check expiry`Alert``withExpiry(float $duration)`Set expiry from now`Action``make(string $label, \Closure(): void $callback)`Factory`Action``->label: non-empty-string`Button label (readonly)`Action``->callback: \Closure(): void`Callback (readonly)`HistoryLog``push(Alert): self`Append alert, return new log`HistoryLog``all(): list`Return all entries`HistoryLog``count(): int`Entry countEnumCases`Position`TopLeft, TopCenter, TopRight, MiddleLeft, MiddleCenter, MiddleRight, BottomLeft, BottomCenter, BottomRight`ToastType`Error, Warning, Info, Success`Overflow`DropOldest, DropNewest, Enqueue`SymbolSet`NerdFont, Unicode, ASCIIShared foundations
------------------

[](#shared-foundations)

- **[candy-buffer](https://github.com/sugarcraft/candy-buffer)** — alert queue composited via `Buffer`; each toast is a sub-`Buffer` composited into the screen `Buffer` for per-cell positioning and overlap resolution.
- **[candy-testing](https://github.com/sugarcraft/candy-testing)** — golden-file snapshot tests via `assertGoldenAnsi()` pin canonical queue layouts.

License
-------

[](#license)

[MIT](LICENSE)

###  Health Score

20

↑

LowBetter than 13% of packages

Maintenance64

Regular maintenance activity

Popularity0

Limited adoption so far

Community6

Small or concentrated contributor base

Maturity11

Early-stage or recently created project

 Bus Factor1

Top contributor holds 100% of commits — single point of failure

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

### Community

Maintainers

![](https://www.gravatar.com/avatar/b1036e0717211b8030b83cbe729e8ba6ba442fdbd5285fb97a39d7dcfe339342?d=identicon)[detain](/maintainers/detain)

---

Top Contributors

[![detain](https://avatars.githubusercontent.com/u/1364504?v=4)](https://github.com/detain "detain (60 commits)")

### Embed Badge

![Health badge](/badges/sugarcraft-sugar-toast/health.svg)

```
[![Health](https://phpackages.com/badges/sugarcraft-sugar-toast/health.svg)](https://phpackages.com/packages/sugarcraft-sugar-toast)
```

###  Alternatives

[jeremykenedy/laravel-phpinfo

phpinfo() in a pretty Laravel blade template

46181.3k](/packages/jeremykenedy-laravel-phpinfo)

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
