@wcstack/state 4.0.0-rc.3 → 4.0.0-rc.5

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.
Files changed (43) hide show
  1. package/README.ja.md +80 -21
  2. package/README.md +81 -22
  3. package/dist/auto.min.js +1 -1
  4. package/dist/index.d.ts +2 -0
  5. package/dist/index.esm.js +1 -1
  6. package/dist/manifest.d.ts +4 -2
  7. package/dist/manifest.esm.js +84 -80
  8. package/dist/parser.esm.js +43 -27
  9. package/dist/split/auto.js +1 -1
  10. package/dist/split/chunks/{chunk-I2V4DGEI.js → chunk-5D34CGCF.js} +1 -1
  11. package/dist/split/chunks/chunk-5MLEMVL3.js +1 -0
  12. package/dist/split/chunks/{chunk-YZ4LWPXN.js → chunk-ACYOJ3NW.js} +1 -1
  13. package/dist/split/chunks/chunk-C3UYMJRT.js +1 -0
  14. package/dist/split/chunks/chunk-COJU24UI.js +1 -0
  15. package/dist/split/chunks/chunk-FVHQWDF4.js +1 -0
  16. package/dist/split/chunks/chunk-FZJY4CF3.js +1 -0
  17. package/dist/split/chunks/chunk-HSMALJSW.js +1 -0
  18. package/dist/split/chunks/chunk-L2BZD5DU.js +1 -0
  19. package/dist/split/chunks/{chunk-Z3EEGBYA.js → chunk-SA2LYPN7.js} +1 -1
  20. package/dist/split/chunks/chunk-VY2XLPFM.js +1 -0
  21. package/dist/split/core.js +1 -1
  22. package/dist/split/features/devtools.js +1 -1
  23. package/dist/split/features/diagnostics.d.ts +3 -3
  24. package/dist/split/features/diagnostics.js +1 -1
  25. package/dist/split/features/formats.d.ts +4 -1
  26. package/dist/split/features/formats.js +1 -1
  27. package/dist/split/features/list-keys.js +1 -1
  28. package/dist/split/features/native-commands.d.ts +31 -0
  29. package/dist/split/features/native-commands.js +1 -0
  30. package/dist/split/features/recursion.js +1 -1
  31. package/dist/split/features/scopes.js +1 -1
  32. package/dist/split/features/ssr.js +1 -1
  33. package/dist/split/features/temporal.js +1 -1
  34. package/dist/wcs-manifest.json +71 -17
  35. package/package.json +1 -1
  36. package/dist/split/chunks/chunk-2PWEFKRB.js +0 -1
  37. package/dist/split/chunks/chunk-5PWMZ75N.js +0 -1
  38. package/dist/split/chunks/chunk-FED2DM4X.js +0 -1
  39. package/dist/split/chunks/chunk-HYEQWIFX.js +0 -1
  40. package/dist/split/chunks/chunk-NPPWJBGJ.js +0 -1
  41. package/dist/split/chunks/chunk-WPSUT5QQ.js +0 -1
  42. package/dist/split/chunks/chunk-YPD4YBJO.js +0 -1
  43. package/dist/split/chunks/chunk-YZUTVCIH.js +0 -1
package/README.ja.md CHANGED
@@ -191,9 +191,9 @@
191
191
  <script type="importmap">
192
192
  {
193
193
  "imports": {
194
- "@wcstack/state/core": "https://cdn.jsdelivr.net/npm/@wcstack/state@4.0.0-rc.3/dist/split/core.js",
195
- "@wcstack/state/features/temporal": "https://cdn.jsdelivr.net/npm/@wcstack/state@4.0.0-rc.3/dist/split/features/temporal.js",
196
- "@wcstack/state/features/scopes": "https://cdn.jsdelivr.net/npm/@wcstack/state@4.0.0-rc.3/dist/split/features/scopes.js"
194
+ "@wcstack/state/core": "https://cdn.jsdelivr.net/npm/@wcstack/state@4.0.0-rc.5/dist/split/core.js",
195
+ "@wcstack/state/features/temporal": "https://cdn.jsdelivr.net/npm/@wcstack/state@4.0.0-rc.5/dist/split/features/temporal.js",
196
+ "@wcstack/state/features/scopes": "https://cdn.jsdelivr.net/npm/@wcstack/state@4.0.0-rc.5/dist/split/features/scopes.js"
197
197
  }
198
198
  }
199
199
  </script>
@@ -226,21 +226,22 @@
226
226
 
227
227
  | エントリ | 足されるもの |
228
228
  |---|---|
229
- | `@wcstack/state/core` | バインディングの本体: `data-wcs`・`{{ }}` とコメントバインディング・`for` / `if`・パス getter・イベント・`$command` / `$on`・24 個のロジックフィルタ(比較・算術・型変換・デフォルト)・`bootstrapState`・`installFeatures` |
229
+ | `@wcstack/state/core` | バインディングの本体: `data-wcs`・`{{ }}` とコメントバインディング・`for` / `if`・パス getter・イベント・`$command` / `$on`・条件の 10 個のフィルタ(`eq` `ne` `not` `lt` `le` `gt` `ge` `truthy` `falsy` `boolean`)・`bootstrapState`・`installFeatures` |
230
230
  | `@wcstack/state/features/temporal` | `$watch`・`$stream` |
231
231
  | `@wcstack/state/features/list-keys` | `$listKeys` |
232
+ | `@wcstack/state/features/native-commands` | ネイティブ要素の `command.<method>:`(`<dialog>` の `showModal()`・`<input>` の `focus()`・`<video>` の `play()` など)—— [ネイティブ要素のコマンド](#ネイティブ要素のコマンド) |
232
233
  | `@wcstack/state/features/scopes` | `bind-component`・`mount=` のボリューム・オーバーレイの公開 getter・DCC(`data-wc-definition`) |
233
234
  | `@wcstack/state/features/recursion` | `$recursion` と `**` パス |
234
235
  | `@wcstack/state/features/ssr` | `enable-ssr`: サーバー描画とハイドレーション |
235
- | `@wcstack/state/features/formats` | 23 個の書式フィルタ(`upper`・`date`・`round`・`truncate` …) |
236
+ | `@wcstack/state/features/formats` | 残りの 37 個のフィルタ: 算術・型変換・デフォルト(`add`・`int`・`coalesce` …)と書式(`upper`・`date`・`round`・`truncate` …) |
236
237
  | `@wcstack/state/features/devtools` | DevTools Hook Protocol への source 登録 |
237
- | `@wcstack/state/features/diagnostics` | エラーメッセージの文章(did-you-mean と lint への案内を含む)と、開発時の警告(束縛や `$watch` のパスが解決しない、`wcs/default-getter-mismatch`)。入れなければ、メッセージは code・番号・値だけになり([エラーメッセージ](#エラーメッセージと番号))、これらの警告は出ない |
238
+ | `@wcstack/state/features/diagnostics` | エラーメッセージの文章(did-you-mean と lint への案内を含む)と、開発時の警告(束縛や `$watch` のパスが解決しない、`wcs/default-getter-mismatch`)。入れなければ、メッセージは番号と値だけになり([エラーメッセージ](#エラーメッセージと番号))、これらの警告は出ず、4.0 で外した 3.x の名前(`$scan`・`$streams`・`$updatedCallback`・`$trackDependency`・`$untrackDependency`)も見つけない |
238
239
  | `@wcstack/state/define` | `defineState` と型だけ — ランタイムは 0 |
239
240
 
240
241
  アドオンが入っていない宣言は黙って無視されません。state の読み込み時に
241
242
  `[wcs/feature-not-installed] $watch needs the add-on @wcstack/state/features/temporal` を throw し
242
243
  (`mount=`・`bind-component`・`data-wc-definition` は同じ形で `scopes` を、`enable-ssr` は `ssr` を
243
- 名指します)、`formats` なしの書式フィルタは束縛計画の段で、アドオン名を挙げた `[wcs/filter-unknown]`
244
+ 名指します)、`formats` なしの `formats` のフィルタは束縛計画の段で、アドオン名を挙げた `[wcs/filter-unknown]`
244
245
  を throw します。install は冪等で — 2 回目の install は読み飛ばされます — どのエントリも core の
245
246
  チャンクを 1 つだけ共有します。アドオンがエンジンの 2 つ目のコピーを抱えることも、**別のアドオン**の
246
247
  コピーを抱えることもありません(アドオンをまたぐ呼び出しは、持ち主のアドオンが install 時に埋める
@@ -252,7 +253,7 @@
252
253
  ページが名指したアドオンを、同じビルドから読み込みます。
253
254
 
254
255
  ```html
255
- <script type="module" src="https://cdn.jsdelivr.net/npm/@wcstack/state@4.0.0-rc.3/dist/split/auto.js"></script>
256
+ <script type="module" src="https://cdn.jsdelivr.net/npm/@wcstack/state@4.0.0-rc.5/dist/split/auto.js"></script>
256
257
  <wcs-state features="scopes diagnostics">
257
258
  <script type="module">
258
259
  export default {
@@ -274,7 +275,7 @@
274
275
  | 何のためか | どの `<wcs-state>` が動き出すよりも前に揃っているべきもの — `mount=` / `bind-component` / DCC の要素が何であるかを決める `scopes` — と、ページの開発補助(`diagnostics`・`devtools`) | その state が必要とするアドオン(`$watch` のための `temporal`、フィルタのための `formats`) |
275
276
  | 誰が読むか | 分割版の auto エントリだけ | すべてのエントリ: 分割版の auto エントリは足りないアドオンを読み込み、それ以外のエントリは入っているかを確かめ、入っていなければその state を `[wcs/feature-not-installed]` で失敗させる |
276
277
 
277
- 名前は `formats`・`diagnostics`・`temporal`・`list-keys`・`scopes`・`recursion`・`ssr`・`devtools` です。
278
+ 名前は `formats`・`diagnostics`・`temporal`・`list-keys`・`scopes`・`recursion`・`ssr`・`devtools`・`native-commands` です。
278
279
  `features=` にそれ以外の名前があると、分割版の auto エントリは `<wcs-state>` を定義する前に
279
280
  `[wcs/feature-unknown]` で失敗します。`$features` にあれば、その state が失敗します(分割版の auto
280
281
  エントリでは `[wcs/feature-unknown]`、それ以外では `[wcs/feature-not-installed]`)。配列でない
@@ -1671,7 +1672,7 @@ export default {
1671
1672
 
1672
1673
  ## フィルタ
1673
1674
 
1674
- 47 種類の組み込みフィルタが入力(DOM → 状態)と出力(状態 → DOM)の両方向で利用できます: core に 24 個のロジックフィルタ(比較・算術・型変換・真偽値 / デフォルト)、`formats` アドオンに 23 個の書式フィルタ(数値フォーマット・文字列・日付 / 時刻)があり、全部入りのエントリには両方が含まれます。
1675
+ 47 種類の組み込みフィルタが入力(DOM → 状態)と出力(状態 → DOM)の両方向で利用できます: core に条件の 10 個のフィルタ(`eq`・`ne`・`not`・`lt`・`le`・`gt`・`ge`・`truthy`・`falsy`・`boolean`)、`formats` アドオンに残りの 37 個(算術・数値フォーマット・文字列・型変換・日付 / 時刻・デフォルト)があり、全部入りのエントリには両方が含まれます。`formats` なしの `/core` で `formats` のフィルタを使うと、束縛計画の段でアドオン名を挙げて失敗します。
1675
1676
 
1676
1677
  3.x が 3.2 の改名の別名として残していた名前(`inc`・`dec`・`fix`・`uc`・`lc`・`cap`・`rep`・`rev`・`pad`・`null`)と `substr` フィルタは存在しません: 未知の名前と同じく失敗し、メッセージが代わりに書くものを示します(`"uc" was renamed "upper" in 3.2 and removed in 4.0 — write "upper".`。`substr(start, length)` は `slice(start, start + length)`)。
1677
1678
 
@@ -2104,7 +2105,7 @@ export default {
2104
2105
  | 部位 | 説明 |
2105
2106
  |---|---|
2106
2107
  | `command.` | 固定の prefix |
2107
- | `<methodName>` | 起動する要素のメソッド。名前は `static wcBindable.commands` に `{ name: "<methodName>" }` として現れること |
2108
+ | `<methodName>` | 起動する要素のメソッド。名前は `static wcBindable.commands` に `{ name: "<methodName>" }` として現れること —— ネイティブ要素では [ネイティブ要素のコマンド](#ネイティブ要素のコマンド) の表にあること |
2108
2109
  | `$command.<tokenName>` | `CommandToken` に解決される明示的な名前空間パス。`<tokenName>` は `$commandTokens` で宣言された名前であること |
2109
2110
 
2110
2111
  右辺は `$command.<tokenName>` と書く必要があります —— ベア名の省略形(`fetchUsers`)は非対応です。`$command.` 名前空間を経由することでバインディングの意図が HTML 上で明示され、トップレベルの state 名前空間を token 名で汚さずに済みます。
@@ -2130,11 +2131,11 @@ class MyFetcher extends HTMLElement {
2130
2131
 
2131
2132
  検証ルール(バインディング時に強制):
2132
2133
 
2133
- - 要素は `protocol: "wc-bindable"` かつ整数 `version` が `1` 以上(現行プロトコルは `1`。1 以上のすべてのバージョンが core 互換)の `static wcBindable` を公開するカスタム要素であること
2134
- - `methodName` は `wcBindable.commands` に(`name` で)現れること
2134
+ - 要素は `protocol: "wc-bindable"` かつ整数 `version` が `1` 以上(現行プロトコルは `1`。1 以上のすべてのバージョンが core 互換)の `static wcBindable` を公開するカスタム要素であること —— または、`native-commands` アドオンがあればネイティブ要素([ネイティブ要素のコマンド](#ネイティブ要素のコマンド))
2135
+ - `methodName` は `wcBindable.commands` に(`name` で)現れること(ネイティブ要素では [ネイティブ要素のコマンド](#ネイティブ要素のコマンド) の表にあること)
2135
2136
  - `<tokenName>` は `$commandTokens` で宣言されていること(`$command.typo` は `[wcs/token-undeclared]` を throw する)
2136
2137
 
2137
- カスタム要素はクラスが定義された時点で検査され、ネイティブ要素はその場で拒否されます(`[wcs/token-misconfigured]`)。ページのバインド中に見つかった違反は `<wcs-state>` の初期化を失敗させます。`for:` / `if:` の行の中で見つかった違反や、ページのバインド後にクラスが定義されて見つかった違反は、そのバインディング 1 本の失敗として `$errorCallback` に届き、行はそのまま構築されます([初期化の失敗](#初期化の失敗))。
2138
+ カスタム要素はクラスが定義された時点で検査され、ネイティブ要素はその場で検査されます —— アドオンが入っていれば(`@wcstack/state` と `/auto` には含まれています)[native-commands](#ネイティブ要素のコマンド) の表と照合し、入っていなければ拒否します(`[wcs/token-misconfigured]` `#1202`)。ページのバインド中に見つかった違反は `<wcs-state>` の初期化を失敗させます。`for:` / `if:` の行の中で見つかった違反や、ページのバインド後にクラスが定義されて見つかった違反は、そのバインディング 1 本の失敗として `$errorCallback` に届き、行はそのまま構築されます([初期化の失敗](#初期化の失敗))。
2138
2139
 
2139
2140
  ### Token API
2140
2141
 
@@ -2192,6 +2193,64 @@ command token は state コードから emit する必要はありません。DO
2192
2193
  <my-list data-wcs="command.reset: $command.reset"></my-list>
2193
2194
  ```
2194
2195
 
2196
+ ### ネイティブ要素のコマンド
2197
+
2198
+ `native-commands` アドオン(`@wcstack/state` と `/auto` には含まれています。`/core` のページは `@wcstack/state/features/native-commands` を入れます)があると、`command.<method>:` は**ネイティブ**要素のメソッドも購読します。ダイアログを開く・入力欄にフォーカスする・動画を再生するといった操作が「state が emit する token」になり、state のコードは要素に手を伸ばしません:
2199
+
2200
+ ```html
2201
+ <button data-wcs="onclick: $command.openEditor">編集</button>
2202
+ <dialog data-wcs="command.showModal: $command.openEditor; command.close: $command.closeEditor">
2203
+ <input data-wcs="value: title">
2204
+ <button data-wcs="onclick: save">保存</button>
2205
+ </dialog>
2206
+ ```
2207
+
2208
+ ```javascript
2209
+ export default {
2210
+ title: "",
2211
+ $commandTokens: ["openEditor", "closeEditor"],
2212
+ async save() {
2213
+ await saveTitle(this.title);
2214
+ this.$command.closeEditor.emit("saved"); // → dialog.close("saved")
2215
+ },
2216
+ };
2217
+ ```
2218
+
2219
+ ネイティブ要素が呼べるのは次の表のメソッドだけです。それ以外のメソッドは、カスタム要素の宣言に無いコマンドと同じく、バインディングの取り付け時に `[wcs/token-misconfigured]`(`#1205`。その要素が呼べるメソッドを列挙する)を throw します:
2220
+
2221
+ | 要素 | メソッド |
2222
+ |---|---|
2223
+ | すべての要素 | `focus` `blur` `click` `scrollIntoView` `showPopover` `hidePopover` `togglePopover` |
2224
+ | `<dialog>` | `show` `showModal` `close` `requestClose` |
2225
+ | `<form>` | `requestSubmit` `checkValidity` `reportValidity` |
2226
+ | `<input>` | `select` `setSelectionRange` `showPicker` `setCustomValidity` `checkValidity` `reportValidity` |
2227
+ | `<textarea>` | `select` `setSelectionRange` `setCustomValidity` `checkValidity` `reportValidity` |
2228
+ | `<select>` | `showPicker` `setCustomValidity` `checkValidity` `reportValidity` |
2229
+ | `<audio>` `<video>` | `play` `pause` `load` |
2230
+
2231
+ 意図して入れていないもの: HTML・属性・木を書き換えるメソッド(`insertAdjacentHTML`・`setAttribute`・`remove` など —— `html:` / `attr.` で束縛してください)、`input` イベント無しでコントロールの値を変えるため state が変化を知らないもの(`form.reset()`・`stepUp()`・`stepDown()`・`setRangeText()` —— state を書き換えてください)、入力検証と `submit` イベントを飛ばす `form.submit()`(`requestSubmit` はどちらも飛ばしません)、そして状態の出力も持つ `@wcstack/fullscreen`・`@wcstack/pointer-lock`・`@wcstack/picture-in-picture` が扱うフルスクリーン / ポインタロック / ピクチャーインピクチャーの要求です。
2232
+
2233
+ - **引数。** ネイティブのメソッドは `emit` の引数を受け取ります。ただし第 1 引数が `Event` なら引数なしで呼びます。`on…: $command.x` のバインディングは `(event, ...listIndexes)` を emit しますが、これを受け取るネイティブメソッドはありません —— `close(event)` は dialog の `returnValue` を `"[object PointerEvent]"` にし、`requestSubmit(event)` は throw します。state からの `emit("saved")`・`emit({ preventScroll: true })`・`emit({ block: "center" })` はそのまま渡ります。カスタム要素のメソッドは従来どおりすべてを受け取ります。
2234
+ - **決めるのは表で、ブラウザではありません。** 表にあるメソッドはどのブラウザでも(サーバーでも)束縛できます。そのメソッドを持たないブラウザ(古いブラウザの `requestClose` など)では、token が emit されたときに呼び出しが失敗し、throw した購読者と同じく報告されます。
2235
+ - **戻り値と例外**はカスタム要素と同じです: `emit` は `checkValidity()` の真偽値や `play()` の `Promise` を返します。throw したメソッド(非モーダルで開いている dialog への `showModal()`、`popover` の無い要素への `showPopover()`)は `console.error` で報告され、ほかの購読者には届きます。reject した `Promise` は捕捉しません: 自動再生の拒否を扱うには、state から `await Promise.all(this.$command.play.emit())` してください。
2236
+ - **描画は後から走ります。** 書き込みはマイクロタスクで描画されるので、`this.editing = true; this.$command.focusTitle.emit();` の emit は、まだ表示されていない入力欄に —— `if:` の中なら、まだ作られていない入力欄に —— 届きます。描かれてから `$renderedCallback` で emit してください:
2237
+
2238
+ ```html
2239
+ <template data-wcs="if: editing">
2240
+ <input data-wcs="value: title; command.focus: $command.focusTitle">
2241
+ </template>
2242
+ ```
2243
+
2244
+ ```javascript
2245
+ $renderedCallback(paths) {
2246
+ if (paths.includes("editing") && this.editing) this.$command.focusTitle.emit();
2247
+ },
2248
+ ```
2249
+
2250
+ - **ユーザー操作。** `showPicker()` と音声つきの `play()` は直前のユーザー操作を必要とします。`on…: $command.x` はイベントの処理の中でメソッドを呼びますが、`await` の後の `emit` では間に合わないことがあります。
2251
+ - **カスタム要素は変わりません**: コマンドは `wcBindable` で宣言し、宣言の無いものは従来どおり `#1202` を throw します。カスタマイズ済み組み込み要素(`<button is="…">`)はネイティブ要素です。
2252
+ - **ボタンだけで開閉が済むなら**、プラットフォームの invoker commands は state を必要としません: `<button commandfor="dlg" command="show-modal">`。state が決めるとき(fetch の後、検証の後)や、invoker commands に無い操作(`focus`・`play`・`scrollIntoView`)に `command.` を使ってください。
2253
+
2195
2254
  ## Event Token(イベントバインディング)
2196
2255
 
2197
2256
  command token はコンポーネントへ *押し込み* ます(state がメソッドを起動)。**event token** はその正確な双対 —— コンポーネントから *引き出し* ます(要素がイベントを dispatch し、state が受信)。両者で要素 ↔ state 境界の双方向をカバーし、どちらの側も相手への参照を一切持ちません。共有されるのは token のみです。
@@ -2353,7 +2412,7 @@ event token は command token と同じ `Token` pub/sub プリミティブを共
2353
2412
 
2354
2413
  ## Stream(`$stream`)
2355
2414
 
2356
- command token / event token が運ぶのは離散的なやり取りです。**`$stream`** は残る形 —— 連続的なフローをカバーします。非同期 producer(async iterable / async generator / `ReadableStream`)を宣言すると、フレームワークがそれを **fold して単一の reactive プロパティに畳み込みます** —— 各チャンクは通常のパス代入を通るため、バインディング・パス getter・`$renderedCallback` は自分で値を代入した場合とまったく同じように反応します。`args` 関数が読んだ state パスが変化すると、実行中の producer は abort され、新しい引数で source が張り直されます(switchMap 型の依存駆動 restart)。stream は `$connectedCallback` 完了後に eager に起動し、要素の disconnect で abort されます。`$stream` は `temporal` アドオンです(全部入りのエントリに含まれる)。3.x の名前 `$streams` は `[wcs/declaration-alias] $streams was removed: write $stream.`(`#1601`)を throw します。
2415
+ command token / event token が運ぶのは離散的なやり取りです。**`$stream`** は残る形 —— 連続的なフローをカバーします。非同期 producer(async iterable / async generator / `ReadableStream`)を宣言すると、フレームワークがそれを **fold して単一の reactive プロパティに畳み込みます** —— 各チャンクは通常のパス代入を通るため、バインディング・パス getter・`$renderedCallback` は自分で値を代入した場合とまったく同じように反応します。`args` 関数が読んだ state パスが変化すると、実行中の producer は abort され、新しい引数で source が張り直されます(switchMap 型の依存駆動 restart)。stream は `$connectedCallback` 完了後に eager に起動し、要素の disconnect で abort されます。`$stream` は `temporal` アドオンです(全部入りのエントリに含まれる)。3.x の名前 `$streams` は、`diagnostics` アドオンが入っていれば(`@wcstack/state`・`/auto`)`[wcs/declaration-alias] $streams was removed: write $stream.`(`#1601`)を throw します。入っていなければ、その宣言は無視されます。
2357
2416
 
2358
2417
  `$renderedCallback` は引き続き binding 駆動です。stream 宣言だけでは headless な購読にならず、その value/status/error の live DOM binding が実際に適用されたときだけ callback の path に現れます。描画せずに stream の値へ反応したい場合は、そのパスに [`$watch`](#watchwatch) を宣言してください。観測契約は [stream リファレンス](docs/streams.md) を参照してください。
2359
2418
 
@@ -2754,7 +2813,7 @@ export default {
2754
2813
 
2755
2814
  状態オブジェクトに `$connectedCallback` / `$disconnectedCallback` / `$renderedCallback` / `$errorCallback` を定義すると、初期化・クリーンアップ・更新時・バインディング失敗時のフックとして利用できます。
2756
2815
 
2757
- > `$renderedCallback` が受けるのは**適用されたバインディング**の更新で、state の更新全体ではありません(それには `$watch`)。3.x の名前 `$updatedCallback` は `[wcs/declaration-alias] $updatedCallback was removed: write $renderedCallback.`(`#1601`)を throw します。
2816
+ > `$renderedCallback` が受けるのは**適用されたバインディング**の更新で、state の更新全体ではありません(それには `$watch`)。3.x の名前 `$updatedCallback` は、`diagnostics` アドオンが入っていれば(`@wcstack/state`・`/auto`)`[wcs/declaration-alias] $updatedCallback was removed: write $renderedCallback.`(`#1601`)を throw します。入っていなければ、その宣言は無視されます。
2758
2817
 
2759
2818
  ```html
2760
2819
  <wcs-state>
@@ -2836,16 +2895,16 @@ li {
2836
2895
 
2837
2896
  ### エラーメッセージと番号
2838
2897
 
2839
- メッセージはすべて `[@wcstack/state]` で始まります。`@wcstack/lint` と VS Code 拡張も検査する事柄についてのメッセージは同じ診断 code(`[wcs/filter-unknown]`)を持ち、ほとんどのメッセージは番号(`#501`)を持ちます。番号の百の位がその code を表します —— 1xx `binding-syntax`、2xx `template-syntax`、3xx `binding-path-missing`、4xx `binding-type-expectation`、5xx `filter-unknown`、6xx `filter-arity`、7xx `getter-cycle`、8xx `getter-depth-exceeded`、9xx `index-arity`、10xx `index-param-range`、11xx `recursion-unsupported`、12xx `token-misconfigured`、13xx `token-undeclared`、14xx `wildcard-rank`、15xx `spread-no-bindable`、16xx `declaration-alias`、17xx `name-alias`。1〜99 は code を持ちません。番号は追加されるだけなので、番号の意味はバージョンをまたいで変わりません。
2898
+ メッセージはすべて `[@wcstack/state]` で始まります。ほとんどのメッセージは番号(`#501`)を持ち、`@wcstack/lint` と VS Code 拡張も検査する事柄についてのメッセージは同じ診断 code(`[wcs/filter-unknown]`)を持ちます。番号の百の位がその code を表します —— 1xx `binding-syntax`、2xx `template-syntax`、3xx `binding-path-missing`、4xx `binding-type-expectation`、5xx `filter-unknown`、6xx `filter-arity`、7xx `getter-cycle`、8xx `getter-depth-exceeded`、9xx `index-arity`、10xx `index-param-range`、11xx `recursion-unsupported`、12xx `token-misconfigured`、13xx `token-undeclared`、14xx `wildcard-rank`、15xx `spread-no-bindable`、16xx `declaration-alias`、17xx `name-alias`。1〜99 は code を持ちません。番号は追加されるだけなので、番号の意味はバージョンをまたいで変わりません。
2840
2899
 
2841
- 番号付きメッセージの文章 —— いちばん近い名前(lint と同じ規則による did-you-mean)、直し方、そして lint が検出できる場合は lint への案内 —— は、`@wcstack/state` と `/auto` に含まれる `diagnostics` アドオンが出します。それを入れていない `/core` のページでは、メッセージは code・番号・表示するはずだった値だけになります:
2900
+ 番号付きメッセージの code と文章 —— いちばん近い名前(lint と同じ規則による did-you-mean)、直し方、そして lint が検出できる場合は lint への案内 —— は、`@wcstack/state` と `/auto` に含まれる `diagnostics` アドオンが出します。それを入れていない `/core` のページでは、メッセージは番号と表示するはずだった値だけになります:
2842
2901
 
2843
2902
  ```
2844
2903
  [@wcstack/state] [wcs/filter-unknown] filter not found: uc. "uc" was renamed "upper" in 3.2 and removed in 4.0 — write "upper". Validate statically: npx @wcstack/lint <file>.
2845
- [@wcstack/state] [wcs/filter-unknown] #501 "uc"
2904
+ [@wcstack/state] #501 "uc"
2846
2905
  ```
2847
2906
 
2848
- 1 行目が `@wcstack/state` と `/auto` の出力、2 行目が `features/diagnostics` なしの `/core` の出力です。`/core` で開発するときは `diagnostics` を入れてください。アドオンなしのページが意図して突き当たる障壁(`[wcs/feature-not-installed]`、`formats` なしの書式フィルタ)は、core の中でも完全な文章です。
2907
+ 1 行目が `@wcstack/state` と `/auto` の出力、2 行目が `features/diagnostics` なしの `/core` の出力です。`/core` で開発するときは `diagnostics` を入れてください: 4.0 で外した 3.x の名前(#1・#1601・#1701)を見つけるのもこのアドオンで、入れていないページはそれらを無視します(その名前の宣言は何もせず、読むと `undefined`)。アドオンなしのページが意図して突き当たる障壁(`[wcs/feature-not-installed]`、`formats` なしの `formats` のフィルタ)は、core の中でも完全な文章です。
2849
2908
 
2850
2909
  <details>
2851
2910
  <summary>番号付きメッセージ</summary>
@@ -3029,7 +3088,7 @@ this.$getAll("matrix.*.*", [row]);
3029
3088
  初期化を失敗させるもの:
3030
3089
 
3031
3090
  - 読めないソース([状態の初期化](#状態の初期化))。
3032
- - 不正な宣言: 削除された名前(`$scan`・`$streams`・`$updatedCallback`)、形の誤った `$behavior` / `$features` / `$commandTokens` / `$eventTokens` / `$on`、アドオンが入っていない宣言(`[wcs/feature-not-installed]`)。
3091
+ - 不正な宣言: 削除された名前(`$scan`・`$streams`・`$updatedCallback`。`diagnostics` アドオンがあるとき)、形の誤った `$behavior` / `$features` / `$commandTokens` / `$eventTokens` / `$on`、アドオンが入っていない宣言(`[wcs/feature-not-installed]`)。
3033
3092
  - ページのバインド中に見つかったマークアップの誤り: 構文エラー、未知のフィルタや誤った引数の個数、wildcard-rank のエラー、フィルタ付きの `for:`、テンプレートの中の `outerHTML:`、クラスが定義済みの要素での wc-bindable の設定ミス。走査はそのエラーで止まります: 文書順でそれより前はバインドされ、後はバインドされません。デプロイの前に `npx @wcstack/lint` を実行してください。
3034
3093
  - 別の `<wcs-state>` がすでにバインドしているルートの上の、2 つ目のルート `<wcs-state>`(`#47`)。state ツリーはルートごとに 1 本です。部分木は `mount=` で接ぎ木してください。
3035
3094
 
package/README.md CHANGED
@@ -192,9 +192,9 @@ leaves features out, it can compose them instead:
192
192
  <script type="importmap">
193
193
  {
194
194
  "imports": {
195
- "@wcstack/state/core": "https://cdn.jsdelivr.net/npm/@wcstack/state@4.0.0-rc.3/dist/split/core.js",
196
- "@wcstack/state/features/temporal": "https://cdn.jsdelivr.net/npm/@wcstack/state@4.0.0-rc.3/dist/split/features/temporal.js",
197
- "@wcstack/state/features/scopes": "https://cdn.jsdelivr.net/npm/@wcstack/state@4.0.0-rc.3/dist/split/features/scopes.js"
195
+ "@wcstack/state/core": "https://cdn.jsdelivr.net/npm/@wcstack/state@4.0.0-rc.5/dist/split/core.js",
196
+ "@wcstack/state/features/temporal": "https://cdn.jsdelivr.net/npm/@wcstack/state@4.0.0-rc.5/dist/split/features/temporal.js",
197
+ "@wcstack/state/features/scopes": "https://cdn.jsdelivr.net/npm/@wcstack/state@4.0.0-rc.5/dist/split/features/scopes.js"
198
198
  }
199
199
  }
200
200
  </script>
@@ -227,21 +227,22 @@ The file names under `dist/split/chunks/` carry a content hash: if you list chun
227
227
 
228
228
  | Entry | What it adds |
229
229
  |---|---|
230
- | `@wcstack/state/core` | The binding engine: `data-wcs`, `{{ }}` and comment bindings, `for` / `if`, path getters, events, `$command` / `$on`, the 24 logic filters (comparison, arithmetic, conversion, defaults), `bootstrapState`, `installFeatures` |
230
+ | `@wcstack/state/core` | The binding engine: `data-wcs`, `{{ }}` and comment bindings, `for` / `if`, path getters, events, `$command` / `$on`, the 10 condition filters (`eq` `ne` `not` `lt` `le` `gt` `ge` `truthy` `falsy` `boolean`), `bootstrapState`, `installFeatures` |
231
231
  | `@wcstack/state/features/temporal` | `$watch`, `$stream` |
232
232
  | `@wcstack/state/features/list-keys` | `$listKeys` |
233
+ | `@wcstack/state/features/native-commands` | `command.<method>:` on native elements (`<dialog>`.`showModal()`, `<input>`.`focus()`, `<video>`.`play()`, …) — [Native Element Commands](#native-element-commands) |
233
234
  | `@wcstack/state/features/scopes` | `bind-component`, `mount=` volumes, overlay exports, DCC (`data-wc-definition`) |
234
235
  | `@wcstack/state/features/recursion` | `$recursion` and `**` paths |
235
236
  | `@wcstack/state/features/ssr` | `enable-ssr`: server rendering and hydration |
236
- | `@wcstack/state/features/formats` | The 23 formatting filters (`upper`, `date`, `round`, `truncate`, …) |
237
+ | `@wcstack/state/features/formats` | The other 37 filters: arithmetic, conversion and defaults (`add`, `int`, `coalesce`, …) and formatting (`upper`, `date`, `round`, `truncate`, …) |
237
238
  | `@wcstack/state/features/devtools` | The DevTools hook protocol source |
238
- | `@wcstack/state/features/diagnostics` | The sentences of error messages, with the did-you-mean and the pointer to lint, and the development-time warnings (a bound or `$watch` path that does not resolve, `wcs/default-getter-mismatch`). Without it a message is its code, its number and its values ([Error messages](#error-messages-and-numbers)), and those warnings are not printed |
239
+ | `@wcstack/state/features/diagnostics` | The sentences of error messages, with the did-you-mean and the pointer to lint, and the development-time warnings (a bound or `$watch` path that does not resolve, `wcs/default-getter-mismatch`). Without it a message is its number and its values ([Error messages](#error-messages-and-numbers)), those warnings are not printed, and the 3.x names 4.0 removed (`$scan`, `$streams`, `$updatedCallback`, `$trackDependency`, `$untrackDependency`) are not detected |
239
240
  | `@wcstack/state/define` | `defineState` and the types only — no runtime at all |
240
241
 
241
242
  A declaration whose add-on is missing does not fail quietly: it throws
242
243
  `[wcs/feature-not-installed] $watch needs the add-on @wcstack/state/features/temporal` when the state
243
244
  is loaded (`mount=`, `bind-component` and `data-wc-definition` name `scopes` the same way, and
244
- `enable-ssr` names `ssr`), and a formatting filter without `formats` throws `[wcs/filter-unknown]`
245
+ `enable-ssr` names `ssr`), and a filter of `formats` without it throws `[wcs/filter-unknown]`
245
246
  naming the add-on when the bindings are planned. Installing is idempotent — an add-on installed
246
247
  again is skipped — and every entry shares one core chunk: an add-on never carries a second copy of
247
248
  the engine, and never a copy of another add-on either (a call across that seam goes through a
@@ -253,7 +254,7 @@ receptacle the owning add-on fills on install).
253
254
  core, and the add-ons the page names from the same build.
254
255
 
255
256
  ```html
256
- <script type="module" src="https://cdn.jsdelivr.net/npm/@wcstack/state@4.0.0-rc.3/dist/split/auto.js"></script>
257
+ <script type="module" src="https://cdn.jsdelivr.net/npm/@wcstack/state@4.0.0-rc.5/dist/split/auto.js"></script>
257
258
  <wcs-state features="scopes diagnostics">
258
259
  <script type="module">
259
260
  export default {
@@ -275,8 +276,8 @@ The add-ons are named in two places, for two different reasons:
275
276
  | What it is for | What must be there before any `<wcs-state>` starts — `scopes`, which decides what a `mount=` / `bind-component` / DCC element is — and the page's development aids (`diagnostics`, `devtools`) | The add-ons that state needs (`temporal` for its `$watch`, `formats` for its filters) |
276
277
  | Who reads it | Only the split auto entry | Every entry: the split auto entry loads the missing add-ons; the other entries check that they are installed and fail the state with `[wcs/feature-not-installed]` otherwise |
277
278
 
278
- The names are `formats`, `diagnostics`, `temporal`, `list-keys`, `scopes`, `recursion`, `ssr` and
279
- `devtools`. Any other name in `features=` makes the split auto entry fail with `[wcs/feature-unknown]`
279
+ The names are `formats`, `diagnostics`, `temporal`, `list-keys`, `scopes`, `recursion`, `ssr`,
280
+ `devtools` and `native-commands`. Any other name in `features=` makes the split auto entry fail with `[wcs/feature-unknown]`
280
281
  before it defines `<wcs-state>`; in `$features` it fails that state (`[wcs/feature-unknown]` on the
281
282
  split auto entry, `[wcs/feature-not-installed]` elsewhere). A `$features` that is not an array throws
282
283
  `#46`, and a volume may not declare one.
@@ -1677,7 +1678,7 @@ Handlers run where the DOM puts them. An outer `#direct` handler runs **before**
1677
1678
 
1678
1679
  ## Filters
1679
1680
 
1680
- 47 built-in filters are available for both input (DOM → state) and output (state → DOM) directions: 24 logic filters in the core (comparison, arithmetic, type conversion, boolean / default) and 23 formatting filters in the `formats` add-on (number formatting, string, date / time), which the full entries include.
1681
+ 47 built-in filters are available for both input (DOM → state) and output (state → DOM) directions: the 10 condition filters in the core (`eq`, `ne`, `not`, `lt`, `le`, `gt`, `ge`, `truthy`, `falsy`, `boolean`) and the other 37 in the `formats` add-on (arithmetic, number formatting, string, type conversion, date / time, defaults), which the full entries include. On `/core` without `formats`, a filter of `formats` fails when the bindings are planned, naming the add-on.
1681
1682
 
1682
1683
  The names 3.x kept as aliases of the 3.2 renames (`inc`, `dec`, `fix`, `uc`, `lc`, `cap`, `rep`, `rev`, `pad`, `null`) and the `substr` filter do not exist: they fail like any unknown name, and the message names what to write instead (`"uc" was renamed "upper" in 3.2 and removed in 4.0 — write "upper".`; `substr(start, length)` is `slice(start, start + length)`).
1683
1684
 
@@ -2114,7 +2115,7 @@ export default {
2114
2115
  | Part | Description |
2115
2116
  |---|---|
2116
2117
  | `command.` | Fixed prefix |
2117
- | `<methodName>` | The element's method to invoke. The name must appear as `{ name: "<methodName>" }` in `static wcBindable.commands` |
2118
+ | `<methodName>` | The element's method to invoke. The name must appear as `{ name: "<methodName>" }` in `static wcBindable.commands` — on a native element, in the table of [Native Element Commands](#native-element-commands) |
2118
2119
  | `$command.<tokenName>` | Explicit namespace path that resolves to a `CommandToken`. `<tokenName>` must be a name declared in `$commandTokens` |
2119
2120
 
2120
2121
  The right-hand side must be written as `$command.<tokenName>` — the bare-name shorthand (`fetchUsers`) is not supported. Going through the `$command.` namespace makes the binding's intent explicit in the HTML and keeps the top-level state namespace free of token names.
@@ -2140,11 +2141,11 @@ class MyFetcher extends HTMLElement {
2140
2141
 
2141
2142
  Validation rules (enforced at binding time):
2142
2143
 
2143
- - The element must be a custom element exposing `static wcBindable` with `protocol: "wc-bindable"` and an integer `version` of `1` or later (the current protocol version is `1`; all versions ≥ 1 are core-compatible)
2144
- - `methodName` must appear (by `name`) in `wcBindable.commands`
2144
+ - The element must be a custom element exposing `static wcBindable` with `protocol: "wc-bindable"` and an integer `version` of `1` or later (the current protocol version is `1`; all versions ≥ 1 are core-compatible) — or a native element, with the `native-commands` add-on ([Native Element Commands](#native-element-commands))
2145
+ - `methodName` must appear (by `name`) in `wcBindable.commands` (on a native element: in the table of [Native Element Commands](#native-element-commands))
2145
2146
  - `<tokenName>` must be declared in `$commandTokens` (`$command.typo` throws `[wcs/token-undeclared]`)
2146
2147
 
2147
- A custom element is checked once its class is defined; a native element is refused at once (`[wcs/token-misconfigured]`). A violation found while the page is bound fails the `<wcs-state>`'s initialization; one found inside a `for:` / `if:` row, or when a class is defined after the page was bound, fails that one binding, which goes to `$errorCallback`, and the row is still built ([Initialization failures](#initialization-failures)).
2148
+ A custom element is checked once its class is defined; a native element at once — against the [native-commands](#native-element-commands) table where the add-on is installed (`@wcstack/state` and `/auto` include it), and refused otherwise (`[wcs/token-misconfigured]` `#1202`). A violation found while the page is bound fails the `<wcs-state>`'s initialization; one found inside a `for:` / `if:` row, or when a class is defined after the page was bound, fails that one binding, which goes to `$errorCallback`, and the row is still built ([Initialization failures](#initialization-failures)).
2148
2149
 
2149
2150
  ### Token API
2150
2151
 
@@ -2202,6 +2203,64 @@ This is pure wiring: the event endpoint is connected to a command-token endpoint
2202
2203
  <my-list data-wcs="command.reset: $command.reset"></my-list>
2203
2204
  ```
2204
2205
 
2206
+ ### Native Element Commands
2207
+
2208
+ With the `native-commands` add-on (`@wcstack/state` and `/auto` include it; a `/core` page installs `@wcstack/state/features/native-commands`), `command.<method>:` also subscribes a **native** element's method. Opening a dialog, focusing an input or playing a video becomes a token the state emits — the state code never reaches for the element:
2209
+
2210
+ ```html
2211
+ <button data-wcs="onclick: $command.openEditor">Edit</button>
2212
+ <dialog data-wcs="command.showModal: $command.openEditor; command.close: $command.closeEditor">
2213
+ <input data-wcs="value: title">
2214
+ <button data-wcs="onclick: save">Save</button>
2215
+ </dialog>
2216
+ ```
2217
+
2218
+ ```javascript
2219
+ export default {
2220
+ title: "",
2221
+ $commandTokens: ["openEditor", "closeEditor"],
2222
+ async save() {
2223
+ await saveTitle(this.title);
2224
+ this.$command.closeEditor.emit("saved"); // → dialog.close("saved")
2225
+ },
2226
+ };
2227
+ ```
2228
+
2229
+ A native element may run only the methods of this table. Any other method throws `[wcs/token-misconfigured]` (`#1205`, naming the methods that element may run) when the binding is attached — like an undeclared command of a custom element:
2230
+
2231
+ | Element | Methods |
2232
+ |---|---|
2233
+ | any element | `focus` `blur` `click` `scrollIntoView` `showPopover` `hidePopover` `togglePopover` |
2234
+ | `<dialog>` | `show` `showModal` `close` `requestClose` |
2235
+ | `<form>` | `requestSubmit` `checkValidity` `reportValidity` |
2236
+ | `<input>` | `select` `setSelectionRange` `showPicker` `setCustomValidity` `checkValidity` `reportValidity` |
2237
+ | `<textarea>` | `select` `setSelectionRange` `setCustomValidity` `checkValidity` `reportValidity` |
2238
+ | `<select>` | `showPicker` `setCustomValidity` `checkValidity` `reportValidity` |
2239
+ | `<audio>` `<video>` | `play` `pause` `load` |
2240
+
2241
+ Left out on purpose: the methods that write HTML, an attribute or the tree (`insertAdjacentHTML`, `setAttribute`, `remove`, … — bind `html:` / `attr.` instead); those that change a control's value without an `input` event, so the state would not see it (`form.reset()`, `stepUp()`, `stepDown()`, `setRangeText()` — write the state instead); `form.submit()`, which skips validation and the `submit` event (`requestSubmit` does neither); and the fullscreen / pointer-lock / picture-in-picture requests, which `@wcstack/fullscreen`, `@wcstack/pointer-lock` and `@wcstack/picture-in-picture` cover along with their state.
2242
+
2243
+ - **Arguments.** A native method receives the `emit` arguments unless the first one is an `Event`. An `on…: $command.x` binding emits `(event, ...listIndexes)`, which no native method takes — `close(event)` would set the dialog's `returnValue` to `"[object PointerEvent]"`, `requestSubmit(event)` would throw — so it is called with none. From the state, `emit("saved")`, `emit({ preventScroll: true })` or `emit({ block: "center" })` pass through. A custom element's method still receives everything.
2244
+ - **The table decides, not the browser.** A method in the table binds in every browser (and on the server). Where a browser lacks it (`requestClose` in an older one), the call fails when the token is emitted and is reported like any subscriber that throws.
2245
+ - **Return values and errors** follow the custom elements': `emit` returns `checkValidity()`'s boolean or `play()`'s `Promise`. A method that throws (`showModal()` on a dialog already open non-modally, `showPopover()` on an element without `popover`) is reported with `console.error`, and the other subscribers still run. A rejected `Promise` is not caught: `await Promise.all(this.$command.play.emit())` from the state to handle an autoplay refusal.
2246
+ - **Rendering comes later.** Writes render in a microtask, so `this.editing = true; this.$command.focusTitle.emit();` reaches an input that is still hidden — or, inside `if:`, not built yet. Emit once it is drawn, from `$renderedCallback`:
2247
+
2248
+ ```html
2249
+ <template data-wcs="if: editing">
2250
+ <input data-wcs="value: title; command.focus: $command.focusTitle">
2251
+ </template>
2252
+ ```
2253
+
2254
+ ```javascript
2255
+ $renderedCallback(paths) {
2256
+ if (paths.includes("editing") && this.editing) this.$command.focusTitle.emit();
2257
+ },
2258
+ ```
2259
+
2260
+ - **User activation.** `showPicker()` and `play()` with sound need a recent user gesture. `on…: $command.x` calls the method inside the event; an `emit` after an `await` may come too late.
2261
+ - **Custom elements are unchanged**: they declare their commands in `wcBindable`, and one without a declaration still throws `#1202`. A customized built-in (`<button is="…">`) is a native element.
2262
+ - **When a button alone opens or closes it**, the platform's invoker commands need no state at all: `<button commandfor="dlg" command="show-modal">`. Use `command.` when the state decides (after a fetch, after validation), or for what invoker commands do not cover (`focus`, `play`, `scrollIntoView`).
2263
+
2205
2264
  ## Event Token (Event Binding)
2206
2265
 
2207
2266
  Command tokens push *into* a component (state invokes a method). **Event tokens** are the exact dual — they pull *out* of a component (an element dispatches an event, state receives it). Together they cover both directions of the element ↔ state boundary, and neither side ever holds a reference to the other — the token is the only shared object.
@@ -2363,7 +2422,7 @@ Two rules cut most of the confusion:
2363
2422
 
2364
2423
  ## Streams (`$stream`)
2365
2424
 
2366
- Command tokens and event tokens carry discrete interactions. **`$stream`** covers the remaining shape: a continuous flow. Declare an async producer (async iterable / async generator / `ReadableStream`) and the framework **folds it into a single reactive property** — each chunk goes through normal path assignment, so bindings, path getters, and `$renderedCallback` react exactly as if you had assigned the value yourself. When a state path read by the `args` function changes, the running producer is aborted and the source is restarted with the new arguments (switchMap-style dependency-driven restart). Streams start eagerly after `$connectedCallback` completes and are aborted when the element disconnects. `$stream` is the `temporal` add-on (in the full entries). The 3.x name `$streams` throws `[wcs/declaration-alias] $streams was removed: write $stream.` (`#1601`).
2425
+ Command tokens and event tokens carry discrete interactions. **`$stream`** covers the remaining shape: a continuous flow. Declare an async producer (async iterable / async generator / `ReadableStream`) and the framework **folds it into a single reactive property** — each chunk goes through normal path assignment, so bindings, path getters, and `$renderedCallback` react exactly as if you had assigned the value yourself. When a state path read by the `args` function changes, the running producer is aborted and the source is restarted with the new arguments (switchMap-style dependency-driven restart). Streams start eagerly after `$connectedCallback` completes and are aborted when the element disconnects. `$stream` is the `temporal` add-on (in the full entries). The 3.x name `$streams` throws `[wcs/declaration-alias] $streams was removed: write $stream.` (`#1601`) where the `diagnostics` add-on is installed (`@wcstack/state`, `/auto`); without it the declaration is ignored.
2367
2426
 
2368
2427
  `$renderedCallback` remains binding-driven: a stream declaration alone is not a headless subscription. Its path appears in the callback only when a live DOM binding for that value/status/error is actually applied. To react to a stream's value without rendering it, declare [`$watch`](#watch-watch) on that path; see the [stream reference](docs/streams.md) for the observation contract.
2369
2428
 
@@ -2764,7 +2823,7 @@ All bindings work inside `<svg>` elements. Use `attr.*` for SVG attributes:
2764
2823
 
2765
2824
  State objects can define `$connectedCallback`, `$disconnectedCallback`, `$renderedCallback`, and `$errorCallback` for initialization, cleanup, update, and binding-failure handling.
2766
2825
 
2767
- > `$renderedCallback` receives updates of **applied bindings**, not every state update (use `$watch` for those). The 3.x name `$updatedCallback` throws `[wcs/declaration-alias] $updatedCallback was removed: write $renderedCallback.` (`#1601`).
2826
+ > `$renderedCallback` receives updates of **applied bindings**, not every state update (use `$watch` for those). The 3.x name `$updatedCallback` throws `[wcs/declaration-alias] $updatedCallback was removed: write $renderedCallback.` (`#1601`) where the `diagnostics` add-on is installed (`@wcstack/state`, `/auto`); without it the declaration is ignored.
2768
2827
 
2769
2828
  ```html
2770
2829
  <wcs-state>
@@ -2846,16 +2905,16 @@ Only a batch that actually has bindings to apply is handed to the tag, so a writ
2846
2905
 
2847
2906
  ### Error messages and numbers
2848
2907
 
2849
- Every message starts with `[@wcstack/state]`. A message about something `@wcstack/lint` and the VS Code extension also check carries the same code (`[wcs/filter-unknown]`), and most messages carry a number (`#501`). The hundreds of a number name its code — 1xx `binding-syntax`, 2xx `template-syntax`, 3xx `binding-path-missing`, 4xx `binding-type-expectation`, 5xx `filter-unknown`, 6xx `filter-arity`, 7xx `getter-cycle`, 8xx `getter-depth-exceeded`, 9xx `index-arity`, 10xx `index-param-range`, 11xx `recursion-unsupported`, 12xx `token-misconfigured`, 13xx `token-undeclared`, 14xx `wildcard-rank`, 15xx `spread-no-bindable`, 16xx `declaration-alias`, 17xx `name-alias`; 1–99 carry no code. Numbers are only ever added, so a number keeps its meaning across versions.
2908
+ Every message starts with `[@wcstack/state]`. Most messages have a number (`#501`), and a message about something `@wcstack/lint` and the VS Code extension also check has the same code (`[wcs/filter-unknown]`). The hundreds of a number name its code — 1xx `binding-syntax`, 2xx `template-syntax`, 3xx `binding-path-missing`, 4xx `binding-type-expectation`, 5xx `filter-unknown`, 6xx `filter-arity`, 7xx `getter-cycle`, 8xx `getter-depth-exceeded`, 9xx `index-arity`, 10xx `index-param-range`, 11xx `recursion-unsupported`, 12xx `token-misconfigured`, 13xx `token-undeclared`, 14xx `wildcard-rank`, 15xx `spread-no-bindable`, 16xx `declaration-alias`, 17xx `name-alias`; 1–99 carry no code. Numbers are only ever added, so a number keeps its meaning across versions.
2850
2909
 
2851
- The sentence of a numbered message — with the nearest name (did-you-mean, by the same rule as the lint), how to fix it, and a pointer to the lint where the lint detects the case — comes from the `diagnostics` add-on, which `@wcstack/state` and `/auto` include. On a `/core` page without it, a message is its code, its number and the values it would show:
2910
+ The code and the sentence of a numbered message — with the nearest name (did-you-mean, by the same rule as the lint), how to fix it, and a pointer to the lint where the lint detects the case — come from the `diagnostics` add-on, which `@wcstack/state` and `/auto` include. On a `/core` page without it, a message is its number and the values it would show:
2852
2911
 
2853
2912
  ```
2854
2913
  [@wcstack/state] [wcs/filter-unknown] filter not found: uc. "uc" was renamed "upper" in 3.2 and removed in 4.0 — write "upper". Validate statically: npx @wcstack/lint <file>.
2855
- [@wcstack/state] [wcs/filter-unknown] #501 "uc"
2914
+ [@wcstack/state] #501 "uc"
2856
2915
  ```
2857
2916
 
2858
- The first line is what `@wcstack/state` and `/auto` print, the second what `/core` without `features/diagnostics` prints. Install `diagnostics` while developing on `/core`. The barriers a page without add-ons meets on purpose (`[wcs/feature-not-installed]`, a formatting filter without `formats`) are full sentences in the core.
2917
+ The first line is what `@wcstack/state` and `/auto` print, the second what `/core` without `features/diagnostics` prints. Install `diagnostics` while developing on `/core`: it also detects the 3.x names 4.0 removed (#1, #1601, #1701), which a page without it ignores (a declaration under one does nothing, reading one gives `undefined`). The barriers a page without add-ons meets on purpose (`[wcs/feature-not-installed]`, a filter of `formats` without it) are full sentences in the core.
2859
2918
 
2860
2919
  <details>
2861
2920
  <summary>The numbered messages</summary>
@@ -3039,7 +3098,7 @@ The header (`#49`) names `mount=`, `bind-component=`, `state=` and `src=` when t
3039
3098
  What fails initialization:
3040
3099
 
3041
3100
  - A source that cannot be read ([State Initialization](#state-initialization)).
3042
- - An invalid declaration: a removed name (`$scan`, `$streams`, `$updatedCallback`), a `$behavior` / `$features` / `$commandTokens` / `$eventTokens` / `$on` of the wrong shape, a declaration whose add-on is not installed (`[wcs/feature-not-installed]`).
3101
+ - An invalid declaration: a removed name (`$scan`, `$streams`, `$updatedCallback`; with the `diagnostics` add-on), a `$behavior` / `$features` / `$commandTokens` / `$eventTokens` / `$on` of the wrong shape, a declaration whose add-on is not installed (`[wcs/feature-not-installed]`).
3043
3102
  - A markup error found while the page is bound: a syntax error, an unknown filter or a wrong argument count, a wildcard-rank error, `for:` with filters, `outerHTML:` in a template, a wc-bindable misconfiguration on an element whose class is already defined. The walk stops at the error: what comes before it in document order is bound, what comes after it is not. Run `npx @wcstack/lint` before you deploy.
3044
3103
  - A second root `<wcs-state>` on a root that another one already binds (`#47`). There is one state tree per root; graft a subtree with `mount=`.
3045
3104