Mercurial
comparison design_system/NOTIFICATIONS.md @ 252:7a7581f040e8
[ui] Add scoped notification component
Co-authored-by: Copilot <[email protected]>
| author | MrJuneJune <me@mrjunejune.com> |
|---|---|
| date | Tue, 04 Aug 2026 11:57:16 -0700 |
| parents | |
| children | fdf3816959cb |
comparison
equal
deleted
inserted
replaced
| 251:117c4d53c9a4 | 252:7a7581f040e8 |
|---|---|
| 1 # Zenbu UI notifications | |
| 2 | |
| 3 `zen-notifications` is a light-DOM, framework-free notification scope. Its | |
| 4 stack is fixed to the bottom-right by default and styled only with `--zen-*` | |
| 5 tokens. | |
| 6 | |
| 7 ```html | |
| 8 <zen-notifications aria-label="Notifications"> | |
| 9 <main id="application"></main> | |
| 10 </zen-notifications> | |
| 11 ``` | |
| 12 | |
| 13 ## Notify | |
| 14 | |
| 15 Descendants dispatch a bubbling, non-composed event: | |
| 16 | |
| 17 ```js | |
| 18 source.dispatchEvent(new CustomEvent("zen-notify", { | |
| 19 bubbles: true, | |
| 20 composed: false, | |
| 21 detail: { | |
| 22 version: 1, | |
| 23 id: "repository-removed", | |
| 24 tone: "success", | |
| 25 message: "Repository removed", | |
| 26 description: "The local checkout was preserved.", | |
| 27 announcement: "polite", | |
| 28 durationMs: 5000, | |
| 29 action: { | |
| 30 token: "opaque-action-token", | |
| 31 label: "Undo", | |
| 32 }, | |
| 33 }, | |
| 34 })); | |
| 35 ``` | |
| 36 | |
| 37 Fields: | |
| 38 | |
| 39 | Field | Values | | |
| 40 | --- | --- | | |
| 41 | `version` | must be `1` | | |
| 42 | `id` | stable non-empty string | | |
| 43 | `tone` | `info`, `success`, `warning`, or `error` | | |
| 44 | `message` | required text | | |
| 45 | `description` | optional text | | |
| 46 | `announcement` | `none`, `polite`, or `assertive` | | |
| 47 | `durationMs` | 250–120000; defaults to 5000 | | |
| 48 | `persistent` | disables timeout when `true` | | |
| 49 | `action` | opaque token and visible label | | |
| 50 | |
| 51 The same ID updates and moves the existing record instead of creating a | |
| 52 duplicate. An ID is announced once during its current lifetime. | |
| 53 | |
| 54 ## Dismiss and actions | |
| 55 | |
| 56 Dismiss through the public method or a scoped event: | |
| 57 | |
| 58 ```js | |
| 59 notifications.dismiss("repository-removed"); | |
| 60 | |
| 61 source.dispatchEvent(new CustomEvent("zen-dismiss-notification", { | |
| 62 bubbles: true, | |
| 63 composed: false, | |
| 64 detail: { version: 1, id: "repository-removed" }, | |
| 65 })); | |
| 66 ``` | |
| 67 | |
| 68 Action buttons dispatch `zen-notification-action` with | |
| 69 `{ version, id, token }`. The opaque token remains in private component state | |
| 70 and is never written into DOM attributes or source markup. | |
| 71 | |
| 72 Removal dispatches `zen-notification-removed` with `{ version, id, reason }`. | |
| 73 | |
| 74 ## Bounds and timing | |
| 75 | |
| 76 - Three records are rendered. | |
| 77 - Twenty additional records may remain queued. | |
| 78 - Overflow evicts the oldest finite record; all-persistent queues reject new | |
| 79 records. | |
| 80 - Queued records do not count down. | |
| 81 - Finite timers pause while hovered, while focus remains inside, and while the | |
| 82 document is hidden. | |
| 83 - Disconnecting clears records, timers, announcements, and internal DOM. | |
| 84 | |
| 85 ## Accessibility | |
| 86 | |
| 87 - Polite and assertive announcements use separate persistent live regions. | |
| 88 - Announcement priority is explicit and independent of tone. | |
| 89 - Announcement messages are serialized so bursts remain observable. | |
| 90 - Actions and dismissal use native buttons. | |
| 91 - New notifications never move focus. | |
| 92 - Keyed rendering preserves focused controls when unrelated records change. | |
| 93 - Forced-colors and reduced-motion modes are supported by component CSS. | |
| 94 | |
| 95 Events with `composed: true` are rejected. This keeps nested application scopes | |
| 96 isolated; adapters crossing a ShadowRoot must validate and redispatch a new | |
| 97 non-composed event deliberately. |