@wcstack/state 3.0.0 → 3.2.0
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 +47 -17
- package/README.md +47 -17
- package/dist/auto.min.js +1 -1
- package/dist/auto.min.js.map +1 -1
- package/dist/define.d.ts +11 -7
- package/dist/index.d.ts +15 -7
- package/dist/index.esm.js +1 -1
- package/dist/index.esm.js.map +1 -1
- package/dist/manifest.d.ts +14 -1
- package/dist/manifest.esm.js +91 -35
- package/dist/parser.esm.js +25 -0
- package/dist/split/chunks/binder.js +1 -1
- package/dist/split/chunks/binder.js.map +1 -1
- package/dist/split/chunks/checkDependency.js +1 -1
- package/dist/split/chunks/declarationAliases.js +2 -0
- package/dist/split/chunks/declarationAliases.js.map +1 -0
- package/dist/split/chunks/filterRegistry.js +1 -1
- package/dist/split/chunks/filterRegistry.js.map +1 -1
- package/dist/split/chunks/mount.js +1 -1
- package/dist/split/chunks/mount.js.map +1 -1
- package/dist/split/chunks/pathDiagnostics.js +1 -1
- package/dist/split/chunks/pathDiagnostics.js.map +1 -1
- package/dist/split/chunks/registerComponents.js +1 -1
- package/dist/split/chunks/registerComponents.js.map +1 -1
- package/dist/split/chunks/setAll.js +1 -1
- package/dist/split/chunks/version.js +1 -1
- package/dist/split/chunks/watchRuntime.js +1 -1
- package/dist/split/core.d.ts +11 -7
- package/dist/split/core.js +1 -1
- package/dist/split/core.js.map +1 -1
- package/dist/split/features/devtools.js +1 -1
- package/dist/split/features/devtools.js.map +1 -1
- package/dist/split/features/diagnostics.js +1 -1
- package/dist/split/features/formats.js +1 -1
- package/dist/split/features/formats.js.map +1 -1
- package/dist/split/features/recursion.js +1 -1
- package/dist/split/features/scopes.js +1 -1
- package/dist/split/features/scopes.js.map +1 -1
- package/dist/split/features/ssr.js +1 -1
- package/dist/split/features/ssr.js.map +1 -1
- package/dist/split/features/temporal.js +1 -1
- package/dist/split/features/temporal.js.map +1 -1
- package/dist/wcs-manifest.json +65 -25
- package/package.json +1 -1
package/README.ja.md
CHANGED
|
@@ -186,9 +186,9 @@
|
|
|
186
186
|
<script type="importmap">
|
|
187
187
|
{
|
|
188
188
|
"imports": {
|
|
189
|
-
"@wcstack/state/core": "https://cdn.jsdelivr.net/npm/@wcstack/state@3.
|
|
190
|
-
"@wcstack/state/features/temporal": "https://cdn.jsdelivr.net/npm/@wcstack/state@3.
|
|
191
|
-
"@wcstack/state/features/scopes": "https://cdn.jsdelivr.net/npm/@wcstack/state@3.
|
|
189
|
+
"@wcstack/state/core": "https://cdn.jsdelivr.net/npm/@wcstack/state@3.2.0/dist/split/core.js",
|
|
190
|
+
"@wcstack/state/features/temporal": "https://cdn.jsdelivr.net/npm/@wcstack/state@3.2.0/dist/split/features/temporal.js",
|
|
191
|
+
"@wcstack/state/features/scopes": "https://cdn.jsdelivr.net/npm/@wcstack/state@3.2.0/dist/split/features/scopes.js"
|
|
192
192
|
}
|
|
193
193
|
}
|
|
194
194
|
</script>
|
|
@@ -335,6 +335,19 @@
|
|
|
335
335
|
|
|
336
336
|
ボリュームは getter・`$watch`・`$listKeys`・`$updatedCallback`・`$connectedCallback`/`$disconnectedCallback` を宣言できます(すべてマウントパス相対)。`$errorCallback` はルート専用です(バインディングの失敗はツリーの所有者へ 1 回だけ報告されます)。読み込み順は自由です(ルートより先に接続されたボリュームは、ルートの登録時に接ぎ木されます)。ルートの `<wcs-state>` が初期化に失敗した場合、その時点で待機していたボリュームは永久に待たずに自分の報告を出して決着します。その報告が終点です —— 孤児として報告されたボリュームは後から自分で接ぎ木し直さないので、あとから修正版のルートを接続しても復帰しません。接ぎ木しないまま決着したボリューム(孤児・ロード失敗・接ぎ木失敗)はマウントの枠を返します。ロード中やルート待ちのあいだに外れたボリュームも枠を返します。そうしたボリュームは、同じ root へ付け直したときはその場で、それ以外は接ぎ木の直前に枠を取り直し、枠が空いていれば従来どおり(外れたままでも)接ぎ木します。外れている間に別のボリュームが枠を取っていた場合は、それを報告して接ぎ木しません。ボリュームの `$connectedCallback` が同期で投げた場合も非同期の失敗と同じく報告に留まり、接ぎ木は済んだものとして扱います。ページを読み直さずに復旧するには、壊れたルートと孤児のボリュームを取り除いて新しい要素を追加してください。接ぎ木済みのボリュームは、外してもデータがツリーに残るので枠を握ったままです。マウントパスは静的パスのみです(`*`・`$`・`#`・`@` は不可)。初期化後に `mount` 属性を変更することはできません — 変更は console 警告付きで無視されます。要素を取り除き、望むパスで新しい要素を追加してください。
|
|
337
337
|
|
|
338
|
+
**ルートのパスをボリュームへ注入する(3.1)。** ボリュームのコードが自分の外のパスを読むには、ボリューム要素の `data-wcs` にコンポーネントの部分マウントと同じ形で書きます:
|
|
339
|
+
|
|
340
|
+
```html
|
|
341
|
+
<wcs-state mount="cart" src="./cart.js" data-wcs="state.taxRate: settings.taxRate"></wcs-state>
|
|
342
|
+
```
|
|
343
|
+
|
|
344
|
+
`cart.js` の中(getter・メソッド・`$watch`・`$listKeys`・ライフサイクル)では `this.taxRate` がルートの `settings.taxRate` を読み書きし、依存も張られるので、`settings.taxRate` が変われば `get total()` も再評価されます。`$watch: { taxRate() {…} }` は `settings.taxRate` の変化で発火し、`$updatedCallback` はその更新を内側の名前 `taxRate` で受けます。注入はボリュームのコードの中の名前です — ページは今までどおり `settings.taxRate` を読み、`cart.taxRate` はツリーにありません。
|
|
345
|
+
|
|
346
|
+
- **1 キーずつ**: 左辺は `state.<キー>` の 1 段です(`state: …` でボリューム全体を動かすことはできません — `mount` を変えてください)。
|
|
347
|
+
- **注入が自前のキーに勝つ**: ボリュームが同名のデータキー(`taxRate: 0`)を宣言していても、その値は接ぎ木されません。同名の getter・setter・メソッドはどちらが `this.taxRate` か曖昧なので、そのボリュームは接ぎ木せずにエラーを報告します。
|
|
348
|
+
- **`#ro`**: `state.taxRate#ro: settings.taxRate` なら読めても書けません。ボリュームのコードからの代入・`$setAll`・書きの `$resolve` は `[wcs/mount-readonly]` を投げます(ルート自身は書けます)。
|
|
349
|
+
- **静的なパスだけ**: 右辺にワイルドカード(`items.*.x`)や `$` 始まりのパスは使えません(ボリュームにはループ文脈がありません)。フィルタも受けません — 変換は getter で行ってください。形の誤りは `[wcs/mount-path-invalid]` で、ロードの前に報告されます。
|
|
350
|
+
|
|
338
351
|
**スコープごとに動くもの**(3.0 で 1 つの表にしました — 要件 B11。ここに無言で無視されるものはありません):
|
|
339
352
|
|
|
340
353
|
| 宣言 | ルートの `<wcs-state>` | ボリューム `<wcs-state mount="p">` | マウントされたコンポーネント(`state: …` 付きの `bind-component`) |
|
|
@@ -435,6 +448,15 @@ property[#modifier]: path[|filter[|filter(args)...]]
|
|
|
435
448
|
| `radio` | ラジオボタングループバインディング(双方向) |
|
|
436
449
|
| `checkbox` | チェックボックスグループの配列バインディング(双方向) |
|
|
437
450
|
| `onclick`, `on*` | イベントハンドラバインディング |
|
|
451
|
+
| `.NAME` | 明示のプロパティ(3.1)— `on` で始まってもイベントにしない |
|
|
452
|
+
|
|
453
|
+
**`on` で始まるプロパティ(3.1)。** 名前が `on` で始まる束縛はイベントになります(`onclick:`)。そのため `online: x` は "line" イベントを待ち、要素の `online` プロパティには書きません。`on` で始まるプロパティに値を書くには、左辺の先頭にドットを付けます:
|
|
454
|
+
|
|
455
|
+
```html
|
|
456
|
+
<my-status data-wcs=".online: isOnline; onclick: refresh"></my-status>
|
|
457
|
+
```
|
|
458
|
+
|
|
459
|
+
ドットの付いた形はドットの無い形と同じ束縛で、イベントにならない点だけが違います(`.value:` は `value:` と同じく双方向、修飾子と入力フィルタもそのまま使えます)。名前空間の語(`.class` / `.attr` / `.style` / `.command` / `.eventToken`)と空の名前は `[wcs/binding-syntax]` で拒否します。
|
|
438
460
|
|
|
439
461
|
### 修飾子
|
|
440
462
|
|
|
@@ -1143,8 +1165,8 @@ export default {
|
|
|
1143
1165
|
| `this.$setAll(path, indexes, value, options?)` | ワイルドカードパスにマッチする全アドレスへ一括書き込み |
|
|
1144
1166
|
| `this.$resolve(path, indexes, value?)` | ワイルドカードパスを特定のインデックスで解決 |
|
|
1145
1167
|
| `this.$postUpdate(path)` | 指定パスの更新通知を手動で発行 |
|
|
1146
|
-
| `this.$
|
|
1147
|
-
| `this.$
|
|
1168
|
+
| `this.$dependOn(path)`(3.2。旧名 `$trackDependency`) | キャッシュ無効化のための依存関係を手動で登録 |
|
|
1169
|
+
| `this.$untracked(fn)`(3.2。旧名 `$untrackDependency`) | fn 実行中の依存追跡を抑止して値を読む |
|
|
1148
1170
|
| `this.$eq(path, key)` / `$eqPath(path, keyPath)` / `$eqIndex(path, level?)` | 鍵付き購読: 「`path` の値はこの行の鍵か」([鍵付き選択](#鍵付き選択eq--eqpath--eqindex)) |
|
|
1149
1171
|
| `this.$stateElement` | `IStateElement` インスタンスへのアクセス |
|
|
1150
1172
|
| `this.$1`, `this.$2`, ... | 現在のループインデックス(1始まりの命名、0始まりの値) |
|
|
@@ -1477,7 +1499,9 @@ export default {
|
|
|
1477
1499
|
|
|
1478
1500
|
## フィルタ
|
|
1479
1501
|
|
|
1480
|
-
|
|
1502
|
+
48 種類の組み込みフィルタが入力(DOM → 状態)と出力(状態 → DOM)の両方向で利用できます。
|
|
1503
|
+
|
|
1504
|
+
**3.2 で一部の名前を改めました**(要件 B12)。表は正式名で、括弧の中が旧名です。旧名は 3.x の間は同じに動き、4.0 で外れます。lint と VS Code 拡張は、旧名に正式名を提案する info(`wcs/name-alias`)を出します。3.1 以前を使うページでは旧名で書いてください。
|
|
1481
1505
|
|
|
1482
1506
|
### 比較
|
|
1483
1507
|
|
|
@@ -1495,8 +1519,8 @@ export default {
|
|
|
1495
1519
|
|
|
1496
1520
|
| フィルタ | 説明 | 例 |
|
|
1497
1521
|
|---|---|---|
|
|
1498
|
-
| `
|
|
1499
|
-
| `
|
|
1522
|
+
| `add(n)`(`inc`) | 加算 | `count\|add(1)` |
|
|
1523
|
+
| `sub(n)`(`dec`) | 減算 | `count\|sub(1)` |
|
|
1500
1524
|
| `mul(n)` | 乗算 | `price\|mul(1.1)` |
|
|
1501
1525
|
| `div(n)` | 除算 | `total\|div(100)` |
|
|
1502
1526
|
| `mod(n)` | 剰余 | `index\|mod(2)` |
|
|
@@ -1507,7 +1531,7 @@ export default {
|
|
|
1507
1531
|
|
|
1508
1532
|
| フィルタ | 説明 | 例 |
|
|
1509
1533
|
|---|---|---|
|
|
1510
|
-
| `
|
|
1534
|
+
| `toFixed(n)`(`fix`) | 固定小数点桁数 | `price\|toFixed(2)` → `"100.00"` |
|
|
1511
1535
|
| `round(n?)` | 四捨五入 | `value\|round(2)` |
|
|
1512
1536
|
| `floor(n?)` | 切り捨て | `value\|floor` |
|
|
1513
1537
|
| `ceil(n?)` | 切り上げ | `value\|ceil` |
|
|
@@ -1519,15 +1543,16 @@ export default {
|
|
|
1519
1543
|
|
|
1520
1544
|
| フィルタ | 説明 | 例 |
|
|
1521
1545
|
|---|---|---|
|
|
1522
|
-
| `uc
|
|
1523
|
-
| `lc
|
|
1524
|
-
| `cap
|
|
1546
|
+
| `upper`(`uc`) | 大文字変換 | `name\|upper` |
|
|
1547
|
+
| `lower`(`lc`) | 小文字変換 | `name\|lower` |
|
|
1548
|
+
| `capitalize`(`cap`) | 先頭大文字 | `name\|capitalize` |
|
|
1525
1549
|
| `trim` | 空白除去 | `text\|trim` |
|
|
1526
1550
|
| `slice(n)` | 文字列スライス | `text\|slice(5)` |
|
|
1527
1551
|
| `substr(start, length)` | 部分文字列 | `text\|substr(0,10)` |
|
|
1528
|
-
| `
|
|
1529
|
-
| `
|
|
1530
|
-
| `
|
|
1552
|
+
| `padStart(n, char?)`(`pad`) | 先頭を埋める(既定 `0`) | `id\|padStart(5,0)` → `"00001"` |
|
|
1553
|
+
| `padEnd(n, char?)` | 末尾を埋める(既定は空白。3.2) | `code\|padEnd(8)` |
|
|
1554
|
+
| `repeat(n)`(`rep`) | 繰り返し | `text\|repeat(3)` |
|
|
1555
|
+
| `reverse`(`rev`) | 反転 | `text\|reverse` |
|
|
1531
1556
|
| `truncate(n, suffix?)` | 切り詰めて省略記号を付加 | `title\|truncate(20)` → `"…"` 付き |
|
|
1532
1557
|
| `join(sep?)` | 配列を連結(既定 `", "`) | `tags\|join` / `tags\|join(/)` |
|
|
1533
1558
|
|
|
@@ -1540,7 +1565,7 @@ export default {
|
|
|
1540
1565
|
| `boolean` | 真偽値に変換 | `value\|boolean` |
|
|
1541
1566
|
| `number` | 数値に変換 | `value\|number` |
|
|
1542
1567
|
| `string` | 文字列に変換 | `value\|string` |
|
|
1543
|
-
| `null
|
|
1568
|
+
| `nullIfEmpty`(`null`) | 空文字を `null` にする(それ以外はそのまま) | `value\|nullIfEmpty` |
|
|
1544
1569
|
|
|
1545
1570
|
### 日付 / 時刻
|
|
1546
1571
|
|
|
@@ -1558,7 +1583,8 @@ export default {
|
|
|
1558
1583
|
|---|---|---|
|
|
1559
1584
|
| `truthy` | truthy チェック — JavaScript の真偽判定そのもので `boolean` と同じ(3.0 から `0n` は偽) | `value\|truthy` |
|
|
1560
1585
|
| `falsy` | falsy チェック(JavaScript の真偽判定。`defaults` も同じ判定を使う) | `value\|falsy` |
|
|
1561
|
-
| `defaults(v)` |
|
|
1586
|
+
| `defaults(v)` | 偽値(`0`・`false`・`""` を含む)のときのフォールバック値 | `name\|defaults(Anonymous)` |
|
|
1587
|
+
| `coalesce(v)` | `null` / `undefined` のときだけのフォールバック値(`0`・`false`・`""` は残す。3.2) | `count\|coalesce(0)` |
|
|
1562
1588
|
|
|
1563
1589
|
### フィルタチェーン
|
|
1564
1590
|
|
|
@@ -2127,6 +2153,8 @@ event token は command token と同じ `Token` pub/sub プリミティブを共
|
|
|
2127
2153
|
|
|
2128
2154
|
## Stream(`$streams`)
|
|
2129
2155
|
|
|
2156
|
+
> **3.2 から宣言キーの正式名は `$stream` です**(要件 B12 — `$watch` / `$scan` と単数で揃えた)。旧名 `$streams` は 3.x の間は同じに動き、4.0 で外れます。両方を宣言すると `[wcs/declaration-alias]` で落ちます。`$streamStatus` / `$streamError` の名前空間は変わりません。3.1 以前では `$streams` と書いてください。
|
|
2157
|
+
|
|
2130
2158
|
command token / event token が運ぶのは離散的なやり取りです。**`$streams`** は残る形 —— 連続的なフローをカバーします。非同期 producer(async iterable / async generator / `ReadableStream`)を宣言すると、フレームワークがそれを **fold して単一の reactive プロパティに畳み込みます** —— 各チャンクは通常のパス代入を通るため、バインディング・パス getter・`$updatedCallback` は自分で値を代入した場合とまったく同じように反応します。`args` 関数が読んだ state パスが変化すると、実行中の producer は abort され、新しい引数で source が張り直されます(switchMap 型の依存駆動 restart)。stream は `$connectedCallback` 完了後に eager に起動し、要素の disconnect で abort されます。
|
|
2131
2159
|
|
|
2132
2160
|
`$updatedCallback` は引き続き binding 駆動です。stream 宣言だけでは headless な購読にならず、その value/status/error の live DOM binding が実際に適用されたときだけ callback の path に現れます。描画せずに stream の値へ反応したい場合は、そのパスに [`$watch`](#watchwatch) を宣言してください。観測契約は [stream リファレンス](docs/streams.md) を参照してください。
|
|
@@ -2596,6 +2624,8 @@ export default {
|
|
|
2596
2624
|
|
|
2597
2625
|
状態オブジェクトに `$connectedCallback` / `$disconnectedCallback` / `$updatedCallback` / `$errorCallback` を定義すると、初期化・クリーンアップ・更新時・バインディング失敗時のフックとして利用できます。
|
|
2598
2626
|
|
|
2627
|
+
> **3.2 から `$updatedCallback` の正式名は `$renderedCallback` です**(要件 B12)。このフックが受けるのは**適用されたバインディング**の更新で、state の更新全体ではない(それには `$watch`)ことを名前で言うためです。旧名は 3.x の間は同じに動き、4.0 で外れます。両方を宣言すると `[wcs/declaration-alias]` で落ちます。3.1 以前では `$updatedCallback` と書いてください。
|
|
2628
|
+
|
|
2599
2629
|
```html
|
|
2600
2630
|
<wcs-state>
|
|
2601
2631
|
<script type="module">
|
package/README.md
CHANGED
|
@@ -187,9 +187,9 @@ leaves features out, it can compose them instead:
|
|
|
187
187
|
<script type="importmap">
|
|
188
188
|
{
|
|
189
189
|
"imports": {
|
|
190
|
-
"@wcstack/state/core": "https://cdn.jsdelivr.net/npm/@wcstack/state@3.
|
|
191
|
-
"@wcstack/state/features/temporal": "https://cdn.jsdelivr.net/npm/@wcstack/state@3.
|
|
192
|
-
"@wcstack/state/features/scopes": "https://cdn.jsdelivr.net/npm/@wcstack/state@3.
|
|
190
|
+
"@wcstack/state/core": "https://cdn.jsdelivr.net/npm/@wcstack/state@3.2.0/dist/split/core.js",
|
|
191
|
+
"@wcstack/state/features/temporal": "https://cdn.jsdelivr.net/npm/@wcstack/state@3.2.0/dist/split/features/temporal.js",
|
|
192
|
+
"@wcstack/state/features/scopes": "https://cdn.jsdelivr.net/npm/@wcstack/state@3.2.0/dist/split/features/scopes.js"
|
|
193
193
|
}
|
|
194
194
|
}
|
|
195
195
|
</script>
|
|
@@ -336,6 +336,19 @@ There is **one state tree per root**. To split state across modules, mount a vol
|
|
|
336
336
|
|
|
337
337
|
A volume may declare getters, `$watch`, `$listKeys`, `$updatedCallback`, and `$connectedCallback`/`$disconnectedCallback` — all relative to its mount path. `$errorCallback` is root-only (a binding failure is reported once, to the tree's owner). Load order does not matter (a volume connected before the root is grafted when the root registers). If the root `<wcs-state>` fails to initialize, the volumes already waiting for it settle with a report of their own instead of waiting forever. That report is the end of the line for those volumes: a volume reported as an orphan does not graft itself later, so connecting a corrected root afterwards does not bring it back. A volume that settles without grafting — orphaned, failed to load, or failed to graft — releases its mount slot, and so does a volume detached while it is still loading or waiting for its root. Such a volume takes the slot back when it is re-attached to the same root, or otherwise just before it grafts, and still grafts as before when the slot is free — even while detached; if another volume took the slot in the meantime, it reports that and does not graft. A synchronous throw from a volume's `$connectedCallback` is reported like an asynchronous one, and the volume counts as grafted. To recover without reloading the page, remove the broken root and the orphaned volumes and add new elements. A grafted volume keeps its slot even when detached, because its data stays in the tree. Mount paths must be static (`*`, `$`, `#`, `@` are rejected). Changing `mount` after the element has initialized is not supported: the change is ignored with a console warning — remove the element and add a new one with the desired path.
|
|
338
338
|
|
|
339
|
+
**Injecting root paths into a volume (3.1).** When a volume's code needs a path outside its own subtree, write the injection on the volume element's `data-wcs`, in the same form as a component's partial mount:
|
|
340
|
+
|
|
341
|
+
```html
|
|
342
|
+
<wcs-state mount="cart" src="./cart.js" data-wcs="state.taxRate: settings.taxRate"></wcs-state>
|
|
343
|
+
```
|
|
344
|
+
|
|
345
|
+
Inside `cart.js` — getters, methods, `$watch`, `$listKeys` and the lifecycle callbacks — `this.taxRate` reads and writes the root's `settings.taxRate`. The read records a dependency, so `get total()` re-evaluates when `settings.taxRate` changes. `$watch: { taxRate() {…} }` fires on changes to `settings.taxRate`, and `$updatedCallback` receives that update under the inner name `taxRate`. The injected name exists only inside the volume's code: the page keeps reading `settings.taxRate`, and the tree has no `cart.taxRate`.
|
|
346
|
+
|
|
347
|
+
- **One key at a time.** The left side is a single `state.<key>`. `state: …` cannot move the whole volume; change `mount` for that.
|
|
348
|
+
- **The injection wins over the volume's own key.** A data key of the same name (`taxRate: 0`) is not grafted. An accessor or method of the same name would make `this.taxRate` ambiguous, so that volume reports an error and does not graft.
|
|
349
|
+
- **`#ro`.** With `state.taxRate#ro: settings.taxRate`, the value can be read but not written. An assignment from the volume's code, `$setAll`, or a writing `$resolve` throws `[wcs/mount-readonly]`; the root itself can still write the path.
|
|
350
|
+
- **Static paths only.** The right side cannot contain a wildcard (`items.*.x`) or start with `$`, because a volume has no loop context. Filters are not accepted either; derive the value in a getter. A malformed injection is reported as `[wcs/mount-path-invalid]` before the volume loads.
|
|
351
|
+
|
|
339
352
|
**What each scope runs** (3.0 states it as one table — requirement B11; nothing here is ignored silently):
|
|
340
353
|
|
|
341
354
|
| Declaration | Root `<wcs-state>` | Volume `<wcs-state mount="p">` | Mounted component (`bind-component` with `state: …`) |
|
|
@@ -436,6 +449,15 @@ The separators `;` and `|` split only outside quotes (3.0), so a quoted filter a
|
|
|
436
449
|
| `radio` | Radio button group binding (two-way) |
|
|
437
450
|
| `checkbox` | Checkbox group binding to array (two-way) |
|
|
438
451
|
| `onclick`, `on*` | Event handler binding |
|
|
452
|
+
| `.NAME` | Explicit property (3.1): never an event, even when the name starts with `on` |
|
|
453
|
+
|
|
454
|
+
**Properties whose names start with `on` (3.1).** A binding whose name starts with `on` is an event binding (`onclick:`). So `online: x` listens for a `"line"` event and never writes the element's `online` property. To bind such a property, put a dot in front of the name:
|
|
455
|
+
|
|
456
|
+
```html
|
|
457
|
+
<my-status data-wcs=".online: isOnline; onclick: refresh"></my-status>
|
|
458
|
+
```
|
|
459
|
+
|
|
460
|
+
The dotted form is the same binding as the undotted one, except that it is never an event. `.value:` is two-way like `value:`, and modifiers and input filters work as usual. A namespace word (`.class`, `.attr`, `.style`, `.command`, `.eventToken`) or an empty name after the dot is rejected with `[wcs/binding-syntax]`.
|
|
439
461
|
|
|
440
462
|
### Modifiers
|
|
441
463
|
|
|
@@ -1144,8 +1166,8 @@ Inside state objects (getters / methods), the following APIs are available via `
|
|
|
1144
1166
|
| `this.$setAll(path, indexes, value, options?)` | Write to every address matching a wildcard path |
|
|
1145
1167
|
| `this.$resolve(path, indexes, value?)` | Resolve a wildcard path with specific indexes |
|
|
1146
1168
|
| `this.$postUpdate(path)` | Manually trigger update notification for a path |
|
|
1147
|
-
| `this.$
|
|
1148
|
-
| `this.$
|
|
1169
|
+
| `this.$dependOn(path)` (3.2; old name `$trackDependency`) | Manually register a dependency for cache invalidation |
|
|
1170
|
+
| `this.$untracked(fn)` (3.2; old name `$untrackDependency`) | Read values inside fn without registering dependencies |
|
|
1149
1171
|
| `this.$eq(path, key)` / `$eqPath(path, keyPath)` / `$eqIndex(path, level?)` | Keyed subscription for "is this row's key the value of `path`?" (see [Keyed selection](#keyed-selection-eq--eqpath--eqindex)) |
|
|
1150
1172
|
| `this.$command.<name>` | Access a `CommandToken` declared in `$commandTokens` (see [Command Token](#command-token-method-binding)) |
|
|
1151
1173
|
| `this.$stateElement` | Access to the `IStateElement` instance |
|
|
@@ -1479,7 +1501,9 @@ export default {
|
|
|
1479
1501
|
|
|
1480
1502
|
## Filters
|
|
1481
1503
|
|
|
1482
|
-
|
|
1504
|
+
48 built-in filters are available for both input (DOM → state) and output (state → DOM) directions.
|
|
1505
|
+
|
|
1506
|
+
**3.2 renamed some filters** (requirement B12). The tables show the canonical names, with the old name in parentheses. The old names work the same through 3.x and are removed in 4.0. Lint and the VS Code extension flag an old name with an info diagnostic (`wcs/name-alias`) that suggests the canonical one. On a page that uses 3.1 or earlier, write the old names.
|
|
1483
1507
|
|
|
1484
1508
|
### Comparison
|
|
1485
1509
|
|
|
@@ -1497,8 +1521,8 @@ export default {
|
|
|
1497
1521
|
|
|
1498
1522
|
| Filter | Description | Example |
|
|
1499
1523
|
|---|---|---|
|
|
1500
|
-
| `
|
|
1501
|
-
| `
|
|
1524
|
+
| `add(n)` (`inc`) | Add | `count\|add(1)` |
|
|
1525
|
+
| `sub(n)` (`dec`) | Subtract | `count\|sub(1)` |
|
|
1502
1526
|
| `mul(n)` | Multiply | `price\|mul(1.1)` |
|
|
1503
1527
|
| `div(n)` | Divide | `total\|div(100)` |
|
|
1504
1528
|
| `mod(n)` | Modulo | `index\|mod(2)` |
|
|
@@ -1509,7 +1533,7 @@ export default {
|
|
|
1509
1533
|
|
|
1510
1534
|
| Filter | Description | Example |
|
|
1511
1535
|
|---|---|---|
|
|
1512
|
-
| `
|
|
1536
|
+
| `toFixed(n)` (`fix`) | Fixed decimal places | `price\|toFixed(2)` → `"100.00"` |
|
|
1513
1537
|
| `round(n?)` | Round | `value\|round(2)` |
|
|
1514
1538
|
| `floor(n?)` | Floor | `value\|floor` |
|
|
1515
1539
|
| `ceil(n?)` | Ceiling | `value\|ceil` |
|
|
@@ -1521,15 +1545,16 @@ export default {
|
|
|
1521
1545
|
|
|
1522
1546
|
| Filter | Description | Example |
|
|
1523
1547
|
|---|---|---|
|
|
1524
|
-
| `uc` | Upper case | `name\|
|
|
1525
|
-
| `lc` | Lower case | `name\|
|
|
1526
|
-
| `cap` | Capitalize | `name\|
|
|
1548
|
+
| `upper` (`uc`) | Upper case | `name\|upper` |
|
|
1549
|
+
| `lower` (`lc`) | Lower case | `name\|lower` |
|
|
1550
|
+
| `capitalize` (`cap`) | Capitalize | `name\|capitalize` |
|
|
1527
1551
|
| `trim` | Trim whitespace | `text\|trim` |
|
|
1528
1552
|
| `slice(n)` | Slice string | `text\|slice(5)` |
|
|
1529
1553
|
| `substr(start, length)` | Substring | `text\|substr(0,10)` |
|
|
1530
|
-
| `
|
|
1531
|
-
| `
|
|
1532
|
-
| `
|
|
1554
|
+
| `padStart(n, char?)` (`pad`) | Pad the start (default `0`) | `id\|padStart(5,0)` → `"00001"` |
|
|
1555
|
+
| `padEnd(n, char?)` | Pad the end (default a space; 3.2) | `code\|padEnd(8)` |
|
|
1556
|
+
| `repeat(n)` (`rep`) | Repeat | `text\|repeat(3)` |
|
|
1557
|
+
| `reverse` (`rev`) | Reverse | `text\|reverse` |
|
|
1533
1558
|
| `truncate(n, suffix?)` | Shorten and append an ellipsis | `title\|truncate(20)` |
|
|
1534
1559
|
| `join(sep?)` | Join an array (default `", "`) | `tags\|join` / `tags\|join(/)` |
|
|
1535
1560
|
|
|
@@ -1542,7 +1567,7 @@ export default {
|
|
|
1542
1567
|
| `boolean` | To boolean | `value\|boolean` |
|
|
1543
1568
|
| `number` | To number | `value\|number` |
|
|
1544
1569
|
| `string` | To string | `value\|string` |
|
|
1545
|
-
| `null` |
|
|
1570
|
+
| `nullIfEmpty` (`null`) | Turn an empty string into `null` (anything else passes through) | `value\|nullIfEmpty` |
|
|
1546
1571
|
|
|
1547
1572
|
### Date / Time
|
|
1548
1573
|
|
|
@@ -1560,7 +1585,8 @@ export default {
|
|
|
1560
1585
|
|---|---|---|
|
|
1561
1586
|
| `truthy` | Truthy check — JavaScript's own truthiness, the same as `boolean` (so `0n` is falsy since 3.0) | `value\|truthy` |
|
|
1562
1587
|
| `falsy` | Falsy check (JavaScript's truthiness; `defaults` uses the same test) | `value\|falsy` |
|
|
1563
|
-
| `defaults(v)` | Fallback value | `name\|defaults(Anonymous)` |
|
|
1588
|
+
| `defaults(v)` | Fallback for any falsy value (`0`, `false` and `""` included) | `name\|defaults(Anonymous)` |
|
|
1589
|
+
| `coalesce(v)` | Fallback for `null` / `undefined` only (`0`, `false` and `""` stay; 3.2) | `count\|coalesce(0)` |
|
|
1564
1590
|
|
|
1565
1591
|
### Filter Chaining
|
|
1566
1592
|
|
|
@@ -2133,6 +2159,8 @@ Two rules cut most of the confusion:
|
|
|
2133
2159
|
|
|
2134
2160
|
## Streams (`$streams`)
|
|
2135
2161
|
|
|
2162
|
+
> **As of 3.2 the canonical declaration key is `$stream`** (requirement B12), singular like `$watch` and `$scan`. The old `$streams` works the same through 3.x and is removed in 4.0. Declaring both fails with `[wcs/declaration-alias]`. The `$streamStatus` / `$streamError` namespaces do not change. On 3.1 or earlier, write `$streams`.
|
|
2163
|
+
|
|
2136
2164
|
Command tokens and event tokens carry discrete interactions. **`$streams`** 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 `$updatedCallback` 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.
|
|
2137
2165
|
|
|
2138
2166
|
`$updatedCallback` 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.
|
|
@@ -2602,6 +2630,8 @@ All bindings work inside `<svg>` elements. Use `attr.*` for SVG attributes:
|
|
|
2602
2630
|
|
|
2603
2631
|
State objects can define `$connectedCallback`, `$disconnectedCallback`, `$updatedCallback`, and `$errorCallback` for initialization, cleanup, update, and binding-failure handling.
|
|
2604
2632
|
|
|
2633
|
+
> **As of 3.2 the canonical name of `$updatedCallback` is `$renderedCallback`** (requirement B12). The hook receives updates of **applied bindings**, not every state update (use `$watch` for those), and the new name says so. The old name works the same through 3.x and is removed in 4.0. Declaring both fails with `[wcs/declaration-alias]`. On 3.1 or earlier, write `$updatedCallback`.
|
|
2634
|
+
|
|
2605
2635
|
```html
|
|
2606
2636
|
<wcs-state>
|
|
2607
2637
|
<script type="module">
|