@wcstack/notification 1.13.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.ja.md +185 -0
- package/README.md +189 -0
- package/dist/auto.js +3 -0
- package/dist/auto.min.js +1 -0
- package/dist/index.d.ts +333 -0
- package/dist/index.esm.js +830 -0
- package/dist/index.esm.js.map +1 -0
- package/dist/index.esm.min.js +2 -0
- package/dist/index.esm.min.js.map +1 -0
- package/dist/sw.d.ts +9 -0
- package/dist/sw.js +89 -0
- package/dist/sw.js.map +1 -0
- package/package.json +76 -0
package/README.ja.md
ADDED
|
@@ -0,0 +1,185 @@
|
|
|
1
|
+
# @wcstack/notification
|
|
2
|
+
|
|
3
|
+
`@wcstack/notification` は wcstack エコシステム向けのヘッドレスなデスクトップ通知コンポーネントです。
|
|
4
|
+
|
|
5
|
+
ビジュアルな UI ウィジェットではありません。
|
|
6
|
+
Notifications API をリアクティブな state と state 駆動のコマンドに変換する**非同期プリミティブノード**です —— `@wcstack/geolocation` がデバイスの位置をリアクティブな state に変えるのと同じ発想です。
|
|
7
|
+
|
|
8
|
+
`@wcstack/state` と組み合わせると、`<wcs-notify>` はパス契約で直接バインドできます:
|
|
9
|
+
|
|
10
|
+
- **command サーフェス**: `request`, `notify`, `close`, `closeAll`
|
|
11
|
+
- **input サーフェス**: `notice`(reactive な表示), `mode`, `body`, `icon`, `badge`, `tag`, `lang`, `dir`, `require-interaction`, `silent`, `renotify`
|
|
12
|
+
- **output state サーフェス**: `permission`, `granted`, `denied`, `prompt`, `unsupported`, `error`, `clicked`, `closed`, `shown`
|
|
13
|
+
|
|
14
|
+
`@wcstack/notification` は [CSBC](https://github.com/csbc-dev/arch/blob/main/README.md)(Core / Shell / Binding Contract)アーキテクチャに従います:
|
|
15
|
+
|
|
16
|
+
- **Core**(`NotificationCore`)が権限・表示(コンストラクタ or Service Worker)・クリック中継を担う
|
|
17
|
+
- **Shell**(`<wcs-notify>`)がそれを DOM 属性・reactive な `notice` 入力・ライフサイクルに接続する
|
|
18
|
+
- **Binding Contract**(`static wcBindable`)が observable な `properties`・`inputs`・`commands` を宣言する
|
|
19
|
+
|
|
20
|
+
## なぜ存在するか —— 双方向が 1 つのタグで完結
|
|
21
|
+
|
|
22
|
+
多くの wcstack IO ノードは片方向に寄っています: `<wcs-permission>` は*監視*のみ(Permissions API に `request()` が無いのでコマンドが無い)、`<wcs-speak>`/`<wcs-listen>` は双対を 2 タグに分割します。Notifications API は違い、**1 つの API で本当に双方向**です:
|
|
23
|
+
|
|
24
|
+
- **表示**はコマンド(state → 要素): `notify(title, options)`。
|
|
25
|
+
- **クリック / クローズ / 表示**はイベント(要素 → state): ユーザーが OS 通知を操作する。
|
|
26
|
+
|
|
27
|
+
つまり `<wcs-notify>` は **command-token**(表示)と **event-token**(クリック)が 1 つのタグに同居する wcstack 初のノードです。さらに `<wcs-permission>` と違い Notifications API には `Notification.requestPermission()` があるため、このノードは**自己完結**します —— 権限の要求/監視と通知の表示を両方担います。
|
|
28
|
+
|
|
29
|
+
> **secure context が必要。** Notifications API は secure context(HTTPS か `localhost`)でのみ動作します。利用できない環境では `<wcs-notify>` は throw せず `permission = "unsupported"` を報告します。権限要求と表示は通常ユーザージェスチャを要するため、タイマーから `notify` を撃っても何も表示されないことがあります。
|
|
30
|
+
|
|
31
|
+
## インストール
|
|
32
|
+
|
|
33
|
+
```bash
|
|
34
|
+
npm install @wcstack/notification
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
## クイックスタート
|
|
38
|
+
|
|
39
|
+
### 1. 要求してから表示する —— state から
|
|
40
|
+
|
|
41
|
+
```html
|
|
42
|
+
<script type="module" src="https://esm.run/@wcstack/state/auto"></script>
|
|
43
|
+
<script type="module" src="https://esm.run/@wcstack/notification/auto"></script>
|
|
44
|
+
|
|
45
|
+
<wcs-state>
|
|
46
|
+
<script type="module">
|
|
47
|
+
export default {
|
|
48
|
+
$commandTokens: ["request", "notify"],
|
|
49
|
+
$eventTokens: ["opened"],
|
|
50
|
+
ask() { this.$command.request.emit(); },
|
|
51
|
+
send() { this.$command.notify.emit("New message", { body: "Tap to open", tag: "chat", data: { room: 7 } }); },
|
|
52
|
+
$on: {
|
|
53
|
+
opened: (state, event) => { console.log("clicked", event.detail); }, // { tag, data, action }
|
|
54
|
+
},
|
|
55
|
+
};
|
|
56
|
+
</script>
|
|
57
|
+
</wcs-state>
|
|
58
|
+
|
|
59
|
+
<wcs-notify data-wcs="
|
|
60
|
+
command.request: $command.request;
|
|
61
|
+
command.notify: $command.notify;
|
|
62
|
+
eventToken.clicked: opened
|
|
63
|
+
"></wcs-notify>
|
|
64
|
+
|
|
65
|
+
<button data-wcs="onclick: ask">Allow notifications</button>
|
|
66
|
+
<button data-wcs="onclick: send">New message</button>
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
`notify.emit(title, options)` の位置引数はそのまま `notify(title, options)` へ素通しされます —— `<wcs-speak>`/`<wcs-fetch>` と同じ引数転送契約です。
|
|
70
|
+
|
|
71
|
+
### 2. reactive な `notice` と 命令的な `notify`
|
|
72
|
+
|
|
73
|
+
```html
|
|
74
|
+
<!-- reactive: 束縛値が「変化」したときに表示(same-value ガードつき)。 -->
|
|
75
|
+
<wcs-notify data-wcs="notice: statusMessage | debounce(1000)"></wcs-notify>
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
`notice` は `notify` の宣言的カウンターパートです: 変化した値を書くと表示し、同値の書き込みは抑制します。命令的な `notify` コマンドは毎回(同じテキストでも)発火します。state 変化のたびに自動発火すると通知スパムの危険があるため、束縛元を debounce し、`tag` を付けて OS 側で de-dup させるとよいです。
|
|
79
|
+
|
|
80
|
+
### 3. 権限をバインド可能な state として
|
|
81
|
+
|
|
82
|
+
```html
|
|
83
|
+
<wcs-notify data-wcs="permission: notifyPerm; granted: canNotify"></wcs-notify>
|
|
84
|
+
|
|
85
|
+
<!-- ブール 1 つでノードから直接 -->
|
|
86
|
+
<div data-wcs="hidden: canNotify">通知を許可してアラートを受け取ってください。</div>
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
`permission` は `"prompt"` / `"granted"` / `"denied"` / `"unsupported"`。Notifications API 自身の `"default"` は `"prompt"` に正規化され、`@wcstack/permission` / `@wcstack/geolocation` と同じ 4 値サーフェスを共有します。
|
|
90
|
+
|
|
91
|
+
### 4. クリックを読む
|
|
92
|
+
|
|
93
|
+
`clicked` / `closed` / `shown` は `{ tag, data, action }` を運びます。`tag` は通知の識別子(あなたの `options.tag`、省略時は生成された `wcs-<n>`)、`data` は `options.data` に渡した値、`action` は Service Worker のアクションボタン id(コンストラクタ経路では常に `""`)です。
|
|
94
|
+
|
|
95
|
+
完全なデモは `examples/state-notification-chat` を参照。
|
|
96
|
+
|
|
97
|
+
## Service Worker / モバイル
|
|
98
|
+
|
|
99
|
+
`new Notification()` はデスクトップでのみ動作します。Android Chrome では throw し、`ServiceWorkerRegistration.showNotification()` が必須です。`<wcs-notify>` は `mode` で経路を選びます:
|
|
100
|
+
|
|
101
|
+
| `mode` | 挙動 |
|
|
102
|
+
| ------------- | --------------------------------------------------------------------------------- |
|
|
103
|
+
| `auto`(既定)| `Notification` コンストラクタを試し、`TypeError`(モバイル)なら SW にフォールバック。 |
|
|
104
|
+
| `constructor` | コンストラクタのみ。`TypeError` は `error` として表面化(フォールバック無し)。 |
|
|
105
|
+
| `sw` | 常に `ServiceWorkerRegistration.showNotification()`。 |
|
|
106
|
+
|
|
107
|
+
SW の `notificationclick` は**あなたの** Service Worker 内で発火し、本パッケージはそこにコードを注入できません。1 行のヘルパを import してクリックをページへ中継してください:
|
|
108
|
+
|
|
109
|
+
```js
|
|
110
|
+
// あなたの sw.js
|
|
111
|
+
import { wireNotificationClicks } from "@wcstack/notification/sw";
|
|
112
|
+
wireNotificationClicks();
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
各クリックを `BroadcastChannel("wcs-notify")`(主)と `clients.postMessage`(フォールバック)で中継し、ページの `NotificationCore` が 2 経路を de-dup して `wcs-notify:click` を発火します。
|
|
116
|
+
|
|
117
|
+
## 属性 / Inputs
|
|
118
|
+
|
|
119
|
+
| 属性 | 型 | 既定 | 説明 |
|
|
120
|
+
| --------------------- | ------- | ------- | --------------------------------------------------------------------------- |
|
|
121
|
+
| `mode` | string | `auto` | 表示経路: `auto` / `sw` / `constructor`。 |
|
|
122
|
+
| `body` | string | `""` | 通知の本文。 |
|
|
123
|
+
| `icon` | string | `""` | アイコン URL。 |
|
|
124
|
+
| `badge` | string | `""` | バッジ URL(モノクロ・モバイル)。 |
|
|
125
|
+
| `tag` | string | `""` | 通知タグ(同一タグの通知は OS が置換する)。 |
|
|
126
|
+
| `lang` | string | `""` | 言語タグ。 |
|
|
127
|
+
| `dir` | string | `""` | 文字方向: `auto` / `ltr` / `rtl`。 |
|
|
128
|
+
| `require-interaction` | boolean | `false` | ユーザーが閉じるまで表示し続ける。 |
|
|
129
|
+
| `silent` | boolean | `false` | 音/バイブを抑制。 |
|
|
130
|
+
| `renotify` | boolean | `false` | 同一タグ通知の置換時に再アラート。 |
|
|
131
|
+
| `manual` | boolean | `false` | reactive な `notice` 経路をミュート(`notify` コマンドは有効なまま)。 |
|
|
132
|
+
|
|
133
|
+
`notice` は reactive な入力(属性なし): 変化した値を書くと通知を表示します。`notify(title, options)` の per-call オプションはこれら属性既定値にキー単位で優先します。
|
|
134
|
+
|
|
135
|
+
## Observable プロパティ(出力)
|
|
136
|
+
|
|
137
|
+
| プロパティ | イベント | 説明 |
|
|
138
|
+
| ------------- | ------------------------------ | ----------------------------------------------------------------- |
|
|
139
|
+
| `permission` | `wcs-notify:permission-change` | `"prompt"` / `"granted"` / `"denied"` / `"unsupported"`、live。 |
|
|
140
|
+
| `granted` / `denied` / `prompt` / `unsupported` | `wcs-notify:permission-change` | `permission` から派生する便宜ブール。 |
|
|
141
|
+
| `error` | `wcs-notify:error` | 失敗時の `{ error, message }`(never-throw)、無ければ `null`。 |
|
|
142
|
+
| `clicked` | `wcs-notify:click` | 直近クリックの `{ tag, data, action }`(event-token 源)。 |
|
|
143
|
+
| `closed` | `wcs-notify:close` | 直近クローズの `{ tag, data, action }`。 |
|
|
144
|
+
| `shown` | `wcs-notify:show` | 直近表示の `{ tag, data, action }`。 |
|
|
145
|
+
|
|
146
|
+
## コマンド
|
|
147
|
+
|
|
148
|
+
| コマンド | 説明 |
|
|
149
|
+
| ------------ | --------------------------------------------------------------------------------- |
|
|
150
|
+
| `request()` | `Notification.requestPermission()`。正規化した権限状態を解決する。 |
|
|
151
|
+
| `notify(title, options?)` | 通知を表示し、識別タグを返す。 |
|
|
152
|
+
| `close(tag)` | `tag` の通知を閉じる。 |
|
|
153
|
+
| `closeAll()` | この要素が表示した全通知を閉じる。 |
|
|
154
|
+
|
|
155
|
+
## 注意・制限
|
|
156
|
+
|
|
157
|
+
- **通知はページより長生きする。** `<wcs-notify>` の切断(または Core の `dispose()`)は購読を解除しますが、開いている通知は**閉じません** —— 通知はページの終了後も残ることが意図です。閉じるには `close` / `closeAll` を使ってください。
|
|
158
|
+
- **Push API はスコープ外。** 本パッケージは Notifications API(ローカル通知)をラップします。サーバ起点の Push は別の関心事です。
|
|
159
|
+
- **サイレント失敗(zero-log)。** wcstack のゼロ依存哲学に沿い、`<wcs-notify>` は決してログ出力も throw もしません。API 不在 → `permission = "unsupported"`、未許可や表示失敗 → `error` プロパティ。`error` / `permission` をバインドして反応してください。
|
|
160
|
+
- **SSR(`@wcstack/server`)。** `static hasConnectedCallbackPromise = true` を宣言し `connectedCallbackPromise` を公開するため、サーバレンダラは接続時の権限プローブが解決するまで待ってからスナップショットします。
|
|
161
|
+
|
|
162
|
+
## ヘッドレス利用(`NotificationCore`)
|
|
163
|
+
|
|
164
|
+
Core は DOM 依存が無く、`@wc-bindable/core` の `bind()` と直接使えます:
|
|
165
|
+
|
|
166
|
+
```typescript
|
|
167
|
+
import { NotificationCore } from "@wcstack/notification";
|
|
168
|
+
|
|
169
|
+
const notify = new NotificationCore();
|
|
170
|
+
await notify.observe(); // 権限 + クリック中継の監視を開始
|
|
171
|
+
await notify.request(); // ユーザーに要求
|
|
172
|
+
|
|
173
|
+
notify.addEventListener("wcs-notify:click", (e) => {
|
|
174
|
+
console.log((e as CustomEvent).detail); // { tag, data, action }
|
|
175
|
+
});
|
|
176
|
+
|
|
177
|
+
const tag = notify.notify("Hello", { body: "world", data: { room: 1 } });
|
|
178
|
+
// あとで:
|
|
179
|
+
notify.close(tag);
|
|
180
|
+
notify.dispose(); // 購読を解除(開いている通知は残る)
|
|
181
|
+
```
|
|
182
|
+
|
|
183
|
+
## ライセンス
|
|
184
|
+
|
|
185
|
+
MIT
|
package/README.md
ADDED
|
@@ -0,0 +1,189 @@
|
|
|
1
|
+
# @wcstack/notification
|
|
2
|
+
|
|
3
|
+
`@wcstack/notification` is a headless desktop-notification component for the wcstack ecosystem.
|
|
4
|
+
|
|
5
|
+
It is not a visual UI widget.
|
|
6
|
+
It is an **async primitive node** that turns the Notifications API into reactive state and a state-driven command — the same way `@wcstack/geolocation` turns the device's location into reactive state.
|
|
7
|
+
|
|
8
|
+
With `@wcstack/state`, `<wcs-notify>` can be bound directly through path contracts:
|
|
9
|
+
|
|
10
|
+
- **command surface**: `request`, `notify`, `close`, `closeAll`
|
|
11
|
+
- **input surface**: `notice` (reactive show), `mode`, `body`, `icon`, `badge`, `tag`, `lang`, `dir`, `require-interaction`, `silent`, `renotify`
|
|
12
|
+
- **output state surface**: `permission`, `granted`, `denied`, `prompt`, `unsupported`, `error`, `clicked`, `closed`, `shown`
|
|
13
|
+
|
|
14
|
+
`@wcstack/notification` follows the [CSBC](https://github.com/csbc-dev/arch/blob/main/README.md) (Core / Shell / Binding Contract) architecture:
|
|
15
|
+
|
|
16
|
+
- **Core** (`NotificationCore`) handles permission, showing (constructor or Service Worker), and click relaying
|
|
17
|
+
- **Shell** (`<wcs-notify>`) connects that to DOM attributes, the reactive `notice` input, and lifecycle
|
|
18
|
+
- **Binding Contract** (`static wcBindable`) declares observable `properties`, `inputs`, and `commands`
|
|
19
|
+
|
|
20
|
+
## Why this exists — both directions in one tag
|
|
21
|
+
|
|
22
|
+
Most wcstack IO nodes lean one way: `<wcs-permission>` only *watches* (it has no commands, because the Permissions API has no `request()`); `<wcs-speak>`/`<wcs-listen>` split a duo across two tags. The Notifications API is different — it is genuinely **bidirectional in a single API**:
|
|
23
|
+
|
|
24
|
+
- **show** is a command (state → element): `notify(title, options)`.
|
|
25
|
+
- **click / close / show** are events (element → state): the user interacting with the OS notification.
|
|
26
|
+
|
|
27
|
+
So `<wcs-notify>` is the first wcstack node where the **command-token** (show) and **event-token** (click) directions live together in one tag. And unlike `<wcs-permission>`, the Notifications API *does* have `Notification.requestPermission()`, so this node is **self-contained**: it both requests/monitors the permission and shows notifications.
|
|
28
|
+
|
|
29
|
+
> **Secure context required.** The Notifications API only works in a secure context (HTTPS, or `localhost`). Where it is absent, `<wcs-notify>` reports `permission = "unsupported"` instead of throwing. Requesting permission and showing also typically require a user gesture — firing `notify` from a timer may show nothing.
|
|
30
|
+
|
|
31
|
+
## Install
|
|
32
|
+
|
|
33
|
+
```bash
|
|
34
|
+
npm install @wcstack/notification
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
## Quick Start
|
|
38
|
+
|
|
39
|
+
### 1. Ask, then show — from state
|
|
40
|
+
|
|
41
|
+
```html
|
|
42
|
+
<script type="module" src="https://esm.run/@wcstack/state/auto"></script>
|
|
43
|
+
<script type="module" src="https://esm.run/@wcstack/notification/auto"></script>
|
|
44
|
+
|
|
45
|
+
<wcs-state>
|
|
46
|
+
<script type="module">
|
|
47
|
+
export default {
|
|
48
|
+
$commandTokens: ["request", "notify"],
|
|
49
|
+
$eventTokens: ["opened"],
|
|
50
|
+
ask() { this.$command.request.emit(); },
|
|
51
|
+
send() { this.$command.notify.emit("New message", { body: "Tap to open", tag: "chat", data: { room: 7 } }); },
|
|
52
|
+
$on: {
|
|
53
|
+
opened: (state, event) => { console.log("clicked", event.detail); }, // { tag, data, action }
|
|
54
|
+
},
|
|
55
|
+
};
|
|
56
|
+
</script>
|
|
57
|
+
</wcs-state>
|
|
58
|
+
|
|
59
|
+
<wcs-notify data-wcs="
|
|
60
|
+
command.request: $command.request;
|
|
61
|
+
command.notify: $command.notify;
|
|
62
|
+
eventToken.clicked: opened
|
|
63
|
+
"></wcs-notify>
|
|
64
|
+
|
|
65
|
+
<button data-wcs="onclick: ask">Allow notifications</button>
|
|
66
|
+
<button data-wcs="onclick: send">New message</button>
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
The positional args of `notify.emit(title, options)` pass straight through to `notify(title, options)` — the same argument-forwarding contract used by `<wcs-speak>`/`<wcs-fetch>`.
|
|
70
|
+
|
|
71
|
+
### 2. Reactive `notice` vs imperative `notify`
|
|
72
|
+
|
|
73
|
+
```html
|
|
74
|
+
<!-- reactive: shows whenever the bound value *changes* (same-value guard). -->
|
|
75
|
+
<wcs-notify data-wcs="notice: statusMessage | debounce(1000)"></wcs-notify>
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
`notice` is the declarative counterpart of `notify`: writing a *changed* value shows it; an identical write is suppressed. The imperative `notify` command fires every call (even the same text). Auto-firing a notification on every state change risks spam, so debounce the bound source and prefer a `tag` so the OS de-dups.
|
|
79
|
+
|
|
80
|
+
### 3. Permission as bindable state
|
|
81
|
+
|
|
82
|
+
```html
|
|
83
|
+
<wcs-notify data-wcs="permission: notifyPerm; granted: canNotify"></wcs-notify>
|
|
84
|
+
|
|
85
|
+
<!-- one boolean, straight from the node -->
|
|
86
|
+
<div data-wcs="hidden: canNotify">Allow notifications to get alerts.</div>
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
`permission` is `"prompt"` / `"granted"` / `"denied"` / `"unsupported"`. The Notifications API's own `"default"` is normalized to `"prompt"`, so this node shares the exact four-value surface of `@wcstack/permission` / `@wcstack/geolocation`.
|
|
90
|
+
|
|
91
|
+
### 4. Reading the click
|
|
92
|
+
|
|
93
|
+
```html
|
|
94
|
+
<wcs-notify data-wcs="command.notify: $command.notify; eventToken.clicked: opened"></wcs-notify>
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
`clicked` / `closed` / `shown` carry `{ tag, data, action }`. `tag` identifies the notification (your `options.tag`, or a generated `wcs-<n>` when omitted); `data` is whatever you passed in `options.data`; `action` is the Service Worker action-button id (always `""` for the constructor backend).
|
|
98
|
+
|
|
99
|
+
See `examples/state-notification-chat` for the full demo.
|
|
100
|
+
|
|
101
|
+
## Service Worker / mobile
|
|
102
|
+
|
|
103
|
+
`new Notification()` works on desktop only. On Android Chrome it throws, and `ServiceWorkerRegistration.showNotification()` is required. `<wcs-notify>` picks the backend per `mode`:
|
|
104
|
+
|
|
105
|
+
| `mode` | Behavior |
|
|
106
|
+
| ------------- | --------------------------------------------------------------------------------- |
|
|
107
|
+
| `auto` (default) | Try the `Notification` constructor; on a `TypeError` (mobile), fall back to the SW. |
|
|
108
|
+
| `constructor` | Constructor only; a `TypeError` surfaces as an `error` (no fallback). |
|
|
109
|
+
| `sw` | Always `ServiceWorkerRegistration.showNotification()`. |
|
|
110
|
+
|
|
111
|
+
The SW's `notificationclick` fires inside **your** Service Worker, which this package cannot inject into. Import the one-line helper so clicks relay back to the page:
|
|
112
|
+
|
|
113
|
+
```js
|
|
114
|
+
// your sw.js
|
|
115
|
+
import { wireNotificationClicks } from "@wcstack/notification/sw";
|
|
116
|
+
wireNotificationClicks();
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
It relays each click over `BroadcastChannel("wcs-notify")` (primary) and `clients.postMessage` (fallback); `NotificationCore` on the page de-dups the two transports and emits `wcs-notify:click`.
|
|
120
|
+
|
|
121
|
+
## Attributes / Inputs
|
|
122
|
+
|
|
123
|
+
| Attribute | Type | Default | Description |
|
|
124
|
+
| --------------------- | ------- | ------- | --------------------------------------------------------------------------- |
|
|
125
|
+
| `mode` | string | `auto` | Show backend: `auto` / `sw` / `constructor`. |
|
|
126
|
+
| `body` | string | `""` | Notification body text. |
|
|
127
|
+
| `icon` | string | `""` | Icon URL. |
|
|
128
|
+
| `badge` | string | `""` | Badge URL (monochrome, mobile). |
|
|
129
|
+
| `tag` | string | `""` | Notification tag (the OS replaces a notification with the same tag). |
|
|
130
|
+
| `lang` | string | `""` | Language tag. |
|
|
131
|
+
| `dir` | string | `""` | Text direction: `auto` / `ltr` / `rtl`. |
|
|
132
|
+
| `require-interaction` | boolean | `false` | Keep the notification visible until the user dismisses it. |
|
|
133
|
+
| `silent` | boolean | `false` | Suppress sound/vibration. |
|
|
134
|
+
| `renotify` | boolean | `false` | Re-alert when replacing a same-tag notification. |
|
|
135
|
+
| `manual` | boolean | `false` | Mute the reactive `notice` path (the `notify` command still works). |
|
|
136
|
+
|
|
137
|
+
`notice` is a reactive input (no attribute): writing a changed value shows a notification. Per-call `notify(title, options)` options win per-key over these attribute defaults.
|
|
138
|
+
|
|
139
|
+
## Observable Properties (outputs)
|
|
140
|
+
|
|
141
|
+
| Property | Event | Description |
|
|
142
|
+
| ------------- | ------------------------------ | ----------------------------------------------------------------- |
|
|
143
|
+
| `permission` | `wcs-notify:permission-change` | `"prompt"` / `"granted"` / `"denied"` / `"unsupported"`, live. |
|
|
144
|
+
| `granted` / `denied` / `prompt` / `unsupported` | `wcs-notify:permission-change` | Convenience booleans derived from `permission`. |
|
|
145
|
+
| `error` | `wcs-notify:error` | `{ error, message }` on a failure (never-throw), else `null`. |
|
|
146
|
+
| `clicked` | `wcs-notify:click` | `{ tag, data, action }` of the last click (event-token source). |
|
|
147
|
+
| `closed` | `wcs-notify:close` | `{ tag, data, action }` of the last close. |
|
|
148
|
+
| `shown` | `wcs-notify:show` | `{ tag, data, action }` of the last shown notification. |
|
|
149
|
+
|
|
150
|
+
## Commands
|
|
151
|
+
|
|
152
|
+
| Command | Description |
|
|
153
|
+
| ------------ | --------------------------------------------------------------------------------- |
|
|
154
|
+
| `request()` | `Notification.requestPermission()`; resolves to the normalized permission state. |
|
|
155
|
+
| `notify(title, options?)` | Show a notification; returns its identifying tag. |
|
|
156
|
+
| `close(tag)` | Dismiss the notification(s) with `tag`. |
|
|
157
|
+
| `closeAll()` | Dismiss every notification this element has shown. |
|
|
158
|
+
|
|
159
|
+
## Notes & limitations
|
|
160
|
+
|
|
161
|
+
- **Notifications outlive the page.** Disconnecting `<wcs-notify>` (or calling `dispose()` on the Core) detaches its subscriptions but does **not** close open notifications — a notification is meant to persist past the page. Use `close` / `closeAll` to dismiss.
|
|
162
|
+
- **Push API is out of scope.** This package wraps the Notifications API (local notifications). Server-initiated Push is a separate concern.
|
|
163
|
+
- **Silent failure handling (zero-log).** Consistent with wcstack's zero-dependency philosophy, `<wcs-notify>` never logs or throws. A missing API → `permission = "unsupported"`; a not-granted permission or a show failure → the `error` property. Bind `error` / `permission` to react.
|
|
164
|
+
- **SSR (`@wcstack/server`).** Declares `static hasConnectedCallbackPromise = true` and exposes `connectedCallbackPromise`, so the server renderer waits for the connect-time permission probe before snapshotting.
|
|
165
|
+
|
|
166
|
+
## Headless usage (`NotificationCore`)
|
|
167
|
+
|
|
168
|
+
The Core has no DOM dependency and can be used directly with `bind()` from `@wc-bindable/core`:
|
|
169
|
+
|
|
170
|
+
```typescript
|
|
171
|
+
import { NotificationCore } from "@wcstack/notification";
|
|
172
|
+
|
|
173
|
+
const notify = new NotificationCore();
|
|
174
|
+
await notify.observe(); // start watching permission + click relays
|
|
175
|
+
await notify.request(); // ask the user
|
|
176
|
+
|
|
177
|
+
notify.addEventListener("wcs-notify:click", (e) => {
|
|
178
|
+
console.log((e as CustomEvent).detail); // { tag, data, action }
|
|
179
|
+
});
|
|
180
|
+
|
|
181
|
+
const tag = notify.notify("Hello", { body: "world", data: { room: 1 } });
|
|
182
|
+
// later:
|
|
183
|
+
notify.close(tag);
|
|
184
|
+
notify.dispose(); // detach subscriptions (open notifications stay)
|
|
185
|
+
```
|
|
186
|
+
|
|
187
|
+
## License
|
|
188
|
+
|
|
189
|
+
MIT
|
package/dist/auto.js
ADDED
package/dist/auto.min.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{bootstrapNotification}from"./index.esm.min.js";bootstrapNotification();
|