Skip to content

Releases: marilenaRM/turbo-toast-bundle

v0.2.1 — Robust toast dismissal

Choose a tag to compare

@marilenaRM marilenaRM released this 13 Jul 16:26
c113e20

Fixed

  • Dismissed toasts could stay in the DOM forever when the consumer app does not load the optional toast.css (or overrides .toast without a transition): transitionend never fires, so the removal never ran. dismiss() now reads the effective transition duration via getComputedStyle and removes the element immediately when it is zero, otherwise keeps the transitionend listener with a setTimeout fallback slightly above the duration. This also covers prefers-reduced-motion and interrupted transitions.
  • transitionend bubbling from descendants (custom <template> toasts containing e.g. a progress bar or a button with its own transition) could tear the toast down early. The handler now reacts only to the toast's own transition (event.target === element).
  • Asymmetric teardown: the transitionend listener is now removed in disconnect() too, not just the fallback timer.

Changed

  • Controller test suite converted to fake timers — deterministic and ~7× faster — with a new regression test for the descendant-bubbling guard.

Full changelog: v0.2.0...v0.2.1

v0.2.0 — Profiler panel

Choose a tag to compare

@marilenaRM marilenaRM released this 09 Jul 06:52

Added

  • Turbo Toast profiler panel: in debug mode, the Symfony profiler shows every toast emitted during the request, per transport (Turbo Stream / cookie), with queued / transported / discarded counts for the cookie path. Discards on server errors are highlighted in the toolbar. Zero overhead outside kernel.debug — the traceable decorators are only wired there.

Changed

  • ToastRendererInterface and ToastStackInterface extracted — the trait, the subscriber and the container aliases now target the interfaces. If you were autowiring the concrete ToastRenderer / ToastStack classes, switch your type-hints to the interfaces.

Full changelog: v0.1.4...v0.2.0

v0.1.4 — Customization hooks & observability

Choose a tag to compare

@marilenaRM marilenaRM released this 09 Jul 05:29

Added

  • Two customization hooks for cookie-rendered toasts, both XSS-safe:
    • a cancelable …toast-container:append event — call preventDefault() and render with your own toast library
    • a <template> target inside the container, cloned per toast — your markup, the message lands as text in [data-toast-message]
  • Optional logging (monolog channel turbo_toast): warning when queued toasts are discarded on a 5xx or dropped over the cookie size budget (no more silent drops), debug on emission

Changed

  • Services now use snake_case ids (marilena_rm_turbo_toast.*) with class aliases for autowiring — decorate or replace by stable id
  • Resolved configuration is carried by a ToastConfig value object instead of scalar constructor args
  • loadExtension() parameter names realigned with AbstractBundle (named-arguments safety)
  • ToastStack is now \Countable

Full changelog: v0.1.3...v0.1.4

v0.1.3 — Internal refactor

Choose a tag to compare

@marilenaRM marilenaRM released this 08 Jul 08:34

Changed

  • The cookie subscriber discards queued toasts on server errors with ToastStack::reset() instead of a dropped drain() — each method now states its intent (reset = throw away, drain = consume). No behavior change.

Full changelog: v0.1.2...v0.1.3

v0.1.2 — Toast dismiss race fix

Choose a tag to compare

@marilenaRM marilenaRM released this 07 Jul 16:38

Fixed

  • A dismiss (click or very short delay) racing the connect() animation frame could re-add the fade-in class after removal, leaving the toast stuck visible with no timer. The pending frame is now cancelled in dismiss() and disconnect().

Added

  • 14 Vitest/jsdom tests for both Stimulus controllers, security paths first: tampered cookie payload rendered as inert text (no XSS), cookie cleared before rendering, no replay on Turbo cache restores, type filtering, malformed payload handling, role by toast type — plus fade-in/auto-dismiss/click behavior
  • CI now runs the JS test suite (node 22)

Full changelog: v0.1.1...v0.1.2

v0.1.1 — Maintenance release

Choose a tag to compare

@marilenaRM marilenaRM released this 07 Jul 16:30

Changed

  • composer fund now lists the Ko-fi page — funding metadata ships in a tagged version
  • Cookie subscriber drains the toast stack once (refactor, no behavior change)

Added

  • Security & hardening design notes: the full threat model behind every protection
  • Twig templates are now linted with twig-cs-fixer (composer lint:twig scripts + CI step)

Full changelog: v0.1.0...v0.1.1

v0.1.0 — Initial release

Choose a tag to compare

@marilenaRM marilenaRM released this 07 Jul 14:56

Session-free flash/toast notifications for Symfony that keep your pages HTTP-cacheable.

One addFlash() is enough to drag the session into an otherwise stateless page and make it uncacheable by Varnish or your CDN. This bundle takes the flash out of the session entirely.

Features

Two session-free transports

  • Turbo Stream$this->toast('Item saved') returns a text/vnd.turbo-stream.html response that appends the toast to the DOM. No redirect, no storage at all. Refuses to render (with an actionable LogicException) when the request does not accept Turbo Streams.
  • Cookie$this->deferToast('Welcome back!') before a classic RedirectResponse: toasts are serialized into a short-lived cookie at kernel.response time and consumed client-side on the next page load. The redirected-to page stays cacheable.

Developer experience

  • TurboToastTrait for controllers: toast(), toasts(), deferToast()
  • {{ turbo_toast_container() }} Twig function renders the container div with Stimulus values injected from the bundle configuration — PHP config and JS can never drift apart
  • Two auto-registered Stimulus controllers: toast (fade-in, auto-dismiss, click to dismiss) and toast-container (cookie consumption on initial load and every turbo:load)
  • Configurable: container id, controller name, default delay, stream template, cookie name
  • Optional minimal stylesheet

Hardening

  • Cookie: SameSite=Lax, Secure on HTTPS, ~3.8 KB budget with graceful overflow, cleared before rendering so Turbo cache restores never replay a toast, rendered with textContent only (client-modifiable input)
  • Responses carrying the cookie are forced private so the Set-Cookie never enters a shared HTTP cache
  • 5xx responses discard queued toasts instead of promising success on the next page
  • ToastStack implements ResetInterface (kernel.reset): no cross-request leak under FrankenPHP worker mode / RoadRunner / Swoole
  • Accessibility: aria-live="polite" container, role="status" / role="alert" by toast type

Requirements

PHP >= 8.3, Symfony 7.x, symfony/ux-turbo + symfony/stimulus-bundle.

Installation

composer require marilenarm/turbo-toast-bundle

See the README for the full documentation, including the honest when (not) to use it section.