@wcstack/state 1.12.0 → 1.13.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 +148 -0
- package/README.md +147 -0
- package/dist/index.esm.js +16 -1
- package/dist/index.esm.js.map +1 -1
- package/dist/index.esm.min.js +1 -1
- package/dist/index.esm.min.js.map +1 -1
- package/package.json +1 -1
package/README.ja.md
CHANGED
|
@@ -96,6 +96,8 @@
|
|
|
96
96
|
- **組み込みフィルタ** — フォーマット、比較、算術、日付など 40 種類
|
|
97
97
|
- **双方向バインディング** — `<input>`, `<select>`, `<textarea>` で自動有効
|
|
98
98
|
- **Web Component バインディング** — Shadow DOM コンポーネントとの双方向状態バインディング
|
|
99
|
+
- **command token** — pub/sub チャネル(`command.<method>: tokenName`)で state から wc-bindable カスタム要素のメソッドを起動
|
|
100
|
+
- **event token** — command token の双対。wc-bindable 要素が dispatch するイベントを `eventToken.<prop>: tokenName` + `$on` マップで state が受信
|
|
99
101
|
- **パス getter** — ドットパスキー getter(`get "users.*.fullName"()`)によるデータツリーの任意の深さへのフラットな仮想プロパティ定義、自動依存追跡・キャッシュ
|
|
100
102
|
- **Mustache 構文** — テキストノードでの `{{ path|filter }}`
|
|
101
103
|
- **複数の状態ソース** — JSON, JS モジュール, インラインスクリプト, API, 属性
|
|
@@ -419,6 +421,8 @@ export default {
|
|
|
419
421
|
<wcs-fetch data-wcs="...: usersFetch; status: alternateStatus"></wcs-fetch>
|
|
420
422
|
```
|
|
421
423
|
|
|
424
|
+
**`undefined` は「無意見」** — 展開された state パスが `undefined` に解決される場合(slot オブジェクトでその input を初期化していない場合など)、プロパティ書き込みは**スキップ**され、要素側の既定値がそのまま生きます。実際に使うパスだけ初期化すれば十分で、`<wcs-fetch>` が `method` / `manual` / `body` を宣言していても `usersFetch: { value: null, loading: false }` だけで動きます。明示的にクリアしたい場合は `null` を代入してください(`null` は常に書き込まれます)。このスキップは spread に限らずすべてのプロパティバインディングに適用され、`config.debug` 時はスキップごとに `console.debug` でログが出ます。
|
|
425
|
+
|
|
422
426
|
**制約事項**:
|
|
423
427
|
|
|
424
428
|
- spread 右辺へのフィルタ(`...: target|filter`)はエラー
|
|
@@ -1245,6 +1249,150 @@ command token は state コードから emit する必要はありません。DO
|
|
|
1245
1249
|
<my-list data-wcs="command.reset: $command.reset"></my-list>
|
|
1246
1250
|
```
|
|
1247
1251
|
|
|
1252
|
+
## Event Token(イベントバインディング)
|
|
1253
|
+
|
|
1254
|
+
command token はコンポーネントへ *押し込み* ます(state がメソッドを起動)。**event token** はその正確な双対 —— コンポーネントから *引き出し* ます(要素がイベントを dispatch し、state が受信)。両者で要素 ↔ state 境界の双方向をカバーし、どちらの側も相手への参照を一切持ちません。共有されるのは token のみです。
|
|
1255
|
+
|
|
1256
|
+
| Token | 方向 | 購読者 | emit する側 |
|
|
1257
|
+
|---|---|---|---|
|
|
1258
|
+
| **command token** | state → 要素 | 要素(`command.<method>:`) | state(`$command.<name>.emit`) |
|
|
1259
|
+
| **event token** | 要素 → state | state(`$on`) | 要素(DOM イベントリスナー) |
|
|
1260
|
+
|
|
1261
|
+
- 要素側は wc-bindable カスタム要素に `eventToken.<property>: <tokenName>` を配線する
|
|
1262
|
+
- state 側は `$eventTokens` でチャネルを宣言し、`$on` マップで受信する
|
|
1263
|
+
- 購読者は `(state, event, ...listIndexes)` で呼び出される —— command token の emit 規約と対称
|
|
1264
|
+
|
|
1265
|
+
### 基本的な使い方
|
|
1266
|
+
|
|
1267
|
+
```html
|
|
1268
|
+
<wcs-state>
|
|
1269
|
+
<script type="module">
|
|
1270
|
+
export default {
|
|
1271
|
+
users: [],
|
|
1272
|
+
error: null,
|
|
1273
|
+
|
|
1274
|
+
$eventTokens: ["userCreated", "createFailed"],
|
|
1275
|
+
$on: {
|
|
1276
|
+
userCreated(state, event) {
|
|
1277
|
+
state.users = state.users.concat(event.detail);
|
|
1278
|
+
},
|
|
1279
|
+
createFailed(state, event) {
|
|
1280
|
+
state.error = event.detail;
|
|
1281
|
+
}
|
|
1282
|
+
}
|
|
1283
|
+
};
|
|
1284
|
+
</script>
|
|
1285
|
+
</wcs-state>
|
|
1286
|
+
|
|
1287
|
+
<!-- emitter — wc-bindable なカスタム要素であること -->
|
|
1288
|
+
<my-form data-wcs="eventToken.created: userCreated; eventToken.error: createFailed"></my-form>
|
|
1289
|
+
```
|
|
1290
|
+
|
|
1291
|
+
`<my-form>` が自身の `created` プロパティに対応する DOM イベントを dispatch すると、`userCreated` token が発火し、`$on.userCreated` ハンドラが `(state, event)` で実行されます。
|
|
1292
|
+
|
|
1293
|
+
### `$eventTokens` 宣言
|
|
1294
|
+
|
|
1295
|
+
`$eventTokens` 配列は、`eventToken.<prop>:` バインディングと `$on` キーが参照できるチャネル名を宣言します。宣言された名前のみが有効です(typo 耐性)。
|
|
1296
|
+
|
|
1297
|
+
```javascript
|
|
1298
|
+
export default {
|
|
1299
|
+
$eventTokens: ["userCreated", "createFailed"],
|
|
1300
|
+
};
|
|
1301
|
+
```
|
|
1302
|
+
|
|
1303
|
+
- エントリは空でない文字列であること
|
|
1304
|
+
- 重複するエントリは初期化時にエラーになる
|
|
1305
|
+
- ここで宣言されたが `$on` に無い token は購読者ゼロ —— emit しても no-op
|
|
1306
|
+
|
|
1307
|
+
### `$on` —— state 側での受信
|
|
1308
|
+
|
|
1309
|
+
`$on` は各 event-token 名をハンドラに対応づけます。state は **第1引数** として渡される(`this` ではない)ため、ハンドラはメソッド省略記法でもアロー関数でも書けます —— `this` を束縛しない点は command token の emit 規約と同じです:
|
|
1310
|
+
|
|
1311
|
+
```javascript
|
|
1312
|
+
$on: {
|
|
1313
|
+
// どちらの形式でも可 —— state は常に第1引数
|
|
1314
|
+
userCreated: (state, event) => { state.lastId = event.detail.id; },
|
|
1315
|
+
rowFailed(state, event, ...listIndexes) {
|
|
1316
|
+
const [i] = listIndexes; // `for` 内から発火した場合のループインデックス
|
|
1317
|
+
state.failedRows = state.failedRows.concat(i);
|
|
1318
|
+
}
|
|
1319
|
+
}
|
|
1320
|
+
```
|
|
1321
|
+
|
|
1322
|
+
- `$on` のすべてのキーは `$eventTokens` で宣言済みであること(さもなくば初期化時に throw)
|
|
1323
|
+
- 各値は関数であること
|
|
1324
|
+
- シグネチャは `(state, event, ...listIndexes)` —— まず DOM の `Event`、続いて内包するループインデックス
|
|
1325
|
+
|
|
1326
|
+
### `eventToken.<property>:` バインディング
|
|
1327
|
+
|
|
1328
|
+
```html
|
|
1329
|
+
<my-target data-wcs="eventToken.error: createFailed"></my-target>
|
|
1330
|
+
```
|
|
1331
|
+
|
|
1332
|
+
| 部位 | 説明 |
|
|
1333
|
+
|---|---|
|
|
1334
|
+
| `eventToken.` | 固定の prefix |
|
|
1335
|
+
| `<property>` | **wcBindable プロパティ名** —— 生の DOM イベント名ではない。実イベント名は `wcBindable.properties[].event` から解決される |
|
|
1336
|
+
| `<tokenName>` | `$eventTokens` で宣言されたベアな event-token 名(command token と違い `$` 名前空間 prefix は付けない) |
|
|
1337
|
+
|
|
1338
|
+
キーを生イベント名ではなくプロパティ名にすることで、command バインディングと同じ `wcBindable` 契約を経由でき、namespaced なイベント名(`ns:evt`)がバインディングの `:` 区切りと衝突しません。フレームワークは `properties[].event` を引いてその実イベントのリスナーを attach します:
|
|
1339
|
+
|
|
1340
|
+
```javascript
|
|
1341
|
+
class MyTarget extends HTMLElement {
|
|
1342
|
+
static wcBindable = {
|
|
1343
|
+
protocol: "wc-bindable", version: 1,
|
|
1344
|
+
properties: [
|
|
1345
|
+
{ name: "error", event: "thing-error" }, // eventToken.error → "thing-error" を listen
|
|
1346
|
+
{ name: "created", event: "thing-created" },
|
|
1347
|
+
],
|
|
1348
|
+
};
|
|
1349
|
+
}
|
|
1350
|
+
```
|
|
1351
|
+
|
|
1352
|
+
検証ルール:
|
|
1353
|
+
|
|
1354
|
+
- 要素は wc-bindable なカスタム要素であること(`static wcBindable`・`protocol: "wc-bindable"`・`version: 1`)。非 wc-bindable 要素は attach 時に拒否される。
|
|
1355
|
+
- `<property>` は `wcBindable.properties` に現れること —— **attach 時** に検証(fail-fast。クラス参照のみで足り、DOM 接続に非依存)。
|
|
1356
|
+
- `<tokenName>` は `$eventTokens` で宣言されていること —— **発火時** に検証。state はイベント発火時に要素の live root から解決されるため、attach 時にノードが detached になりうる `for` / `if` ブロック内や SSR ハイドレーション後でも機能する。
|
|
1357
|
+
- 修飾子 `#prevent` / `#stop` は通常のイベントバインディングと同様に機能する: `eventToken.error#prevent: createFailed`。
|
|
1358
|
+
|
|
1359
|
+
### ループ内での使用
|
|
1360
|
+
|
|
1361
|
+
emitter が `for` ブロック内にある場合、`on*` ハンドラと同じく、内包するループインデックスがイベントの後ろに付与されます:
|
|
1362
|
+
|
|
1363
|
+
```html
|
|
1364
|
+
<template data-wcs="for: rows">
|
|
1365
|
+
<my-row data-wcs="eventToken.failed: rowFailed"></my-row>
|
|
1366
|
+
</template>
|
|
1367
|
+
```
|
|
1368
|
+
|
|
1369
|
+
```javascript
|
|
1370
|
+
$on: {
|
|
1371
|
+
rowFailed(state, event, ...listIndexes) {
|
|
1372
|
+
const [i] = listIndexes; // 発火した行のインデックス
|
|
1373
|
+
state.failedRows = state.failedRows.concat(i);
|
|
1374
|
+
}
|
|
1375
|
+
}
|
|
1376
|
+
```
|
|
1377
|
+
|
|
1378
|
+
### ファンインとチェイン
|
|
1379
|
+
|
|
1380
|
+
複数の要素が同じ token を配線できます(`eventToken.x: shared`)—— すべての dispatch が1つの `$on` ハンドラに届き、command token のファンアウトと対称です。さらに `$on` ハンドラは `state` を受け取るため、そこから command token を再 emit して 要素 → state → 要素 のチェインを組めます:
|
|
1381
|
+
|
|
1382
|
+
```javascript
|
|
1383
|
+
$commandTokens: ["doRefresh"],
|
|
1384
|
+
$eventTokens: ["completed"],
|
|
1385
|
+
$on: {
|
|
1386
|
+
completed(state) {
|
|
1387
|
+
state.$command.doRefresh.emit(); // event in → command out
|
|
1388
|
+
}
|
|
1389
|
+
}
|
|
1390
|
+
```
|
|
1391
|
+
|
|
1392
|
+
### Token API
|
|
1393
|
+
|
|
1394
|
+
event token は command token と同じ `Token` pub/sub プリミティブを共有します —— `name` / `size` / `subscribe` / `unsubscribe` / `emit`、subscribe 順の保持つき([Token API](#token-api) 参照)。token はイベントごとに registry から解決されるため、`setInitialState()` による再構築後も最新の `$on` 購読者に届きます。所有する `<wcs-state>` が disconnect されると、event-token registry はクリアされます。
|
|
1395
|
+
|
|
1248
1396
|
## Inputs と属性ミラー
|
|
1249
1397
|
|
|
1250
1398
|
`wcBindable.inputs` は一方向のプロパティ入力(state → 要素)を宣言します。エントリに `attribute` を設定すると、フレームワークはプロパティを書き込むたびにその値を当該 HTML 属性へも書き込むため、`attributeChangedCallback`・CSS の属性セレクタ・DevTools がすべてプロパティ値と同期し続けます。
|
package/README.md
CHANGED
|
@@ -97,6 +97,7 @@ That's it. No build, no bootstrap code, no framework.
|
|
|
97
97
|
- **Two-way binding** — automatic for `<input>`, `<select>`, `<textarea>`
|
|
98
98
|
- **Web Component binding** — bidirectional state binding with Shadow DOM components
|
|
99
99
|
- **Command tokens** — invoke methods on wc-bindable custom elements from state via a pub/sub channel (`command.<method>: tokenName`)
|
|
100
|
+
- **Event tokens** — the dual of command tokens: receive a wc-bindable element's dispatched events in state via `eventToken.<prop>: tokenName` + the `$on` map
|
|
100
101
|
- **Path getters** — dot-path key getters (`get "users.*.fullName"()`) for virtual properties at any depth in a data tree, all defined flat in one place with automatic dependency tracking and caching
|
|
101
102
|
- **Mustache syntax** — `{{ path|filter }}` in text nodes
|
|
102
103
|
- **Multiple state sources** — JSON, JS module, inline script, API, attribute
|
|
@@ -420,6 +421,8 @@ Runtime reads `customClass.wcBindable.properties + inputs` and expands each name
|
|
|
420
421
|
<wcs-fetch data-wcs="...: usersFetch; status: alternateStatus"></wcs-fetch>
|
|
421
422
|
```
|
|
422
423
|
|
|
424
|
+
**`undefined` is "no opinion"** — when an expanded state path resolves to `undefined` (e.g. the slot object doesn't initialize that input), the property write is **skipped** and the element keeps its own default. You only need to initialize the paths you actually use; `usersFetch: { value: null, loading: false }` is enough even though `<wcs-fetch>` also declares `method` / `manual` / `body`. To explicitly clear a value, assign `null` — `null` is always written. (This skip applies to every property binding, not just spread; with `config.debug` each skipped write is logged via `console.debug`.)
|
|
425
|
+
|
|
423
426
|
**Constraints**:
|
|
424
427
|
|
|
425
428
|
- Filters on the spread target (`...: target|filter`) are rejected.
|
|
@@ -1247,6 +1250,150 @@ This is pure wiring: the event endpoint is connected to a command-token endpoint
|
|
|
1247
1250
|
<my-list data-wcs="command.reset: $command.reset"></my-list>
|
|
1248
1251
|
```
|
|
1249
1252
|
|
|
1253
|
+
## Event Token (Event Binding)
|
|
1254
|
+
|
|
1255
|
+
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.
|
|
1256
|
+
|
|
1257
|
+
| Token | Direction | Subscribes | Emits |
|
|
1258
|
+
|---|---|---|---|
|
|
1259
|
+
| **Command token** | state → element | element (`command.<method>:`) | state (`$command.<name>.emit`) |
|
|
1260
|
+
| **Event token** | element → state | state (`$on`) | element (DOM event listener) |
|
|
1261
|
+
|
|
1262
|
+
- The element wires `eventToken.<property>: <tokenName>` on a wc-bindable custom element.
|
|
1263
|
+
- State declares channels with `$eventTokens` and receives them with the `$on` map.
|
|
1264
|
+
- Subscribers are called as `(state, event, ...listIndexes)` — symmetric with the command-token emit convention.
|
|
1265
|
+
|
|
1266
|
+
### Basic Usage
|
|
1267
|
+
|
|
1268
|
+
```html
|
|
1269
|
+
<wcs-state>
|
|
1270
|
+
<script type="module">
|
|
1271
|
+
export default {
|
|
1272
|
+
users: [],
|
|
1273
|
+
error: null,
|
|
1274
|
+
|
|
1275
|
+
$eventTokens: ["userCreated", "createFailed"],
|
|
1276
|
+
$on: {
|
|
1277
|
+
userCreated(state, event) {
|
|
1278
|
+
state.users = state.users.concat(event.detail);
|
|
1279
|
+
},
|
|
1280
|
+
createFailed(state, event) {
|
|
1281
|
+
state.error = event.detail;
|
|
1282
|
+
}
|
|
1283
|
+
}
|
|
1284
|
+
};
|
|
1285
|
+
</script>
|
|
1286
|
+
</wcs-state>
|
|
1287
|
+
|
|
1288
|
+
<!-- Emitters — must be wc-bindable custom elements -->
|
|
1289
|
+
<my-form data-wcs="eventToken.created: userCreated; eventToken.error: createFailed"></my-form>
|
|
1290
|
+
```
|
|
1291
|
+
|
|
1292
|
+
When `<my-form>` dispatches the DOM event mapped to its `created` property, the `userCreated` token fires and the `$on.userCreated` handler runs with `(state, event)`.
|
|
1293
|
+
|
|
1294
|
+
### `$eventTokens` Declaration
|
|
1295
|
+
|
|
1296
|
+
The `$eventTokens` array declares the channel names that `eventToken.<prop>:` bindings and `$on` keys may reference. Only declared names are valid (typo resistance).
|
|
1297
|
+
|
|
1298
|
+
```javascript
|
|
1299
|
+
export default {
|
|
1300
|
+
$eventTokens: ["userCreated", "createFailed"],
|
|
1301
|
+
};
|
|
1302
|
+
```
|
|
1303
|
+
|
|
1304
|
+
- Entries must be non-empty strings
|
|
1305
|
+
- Duplicate entries throw an error at initialization
|
|
1306
|
+
- A token declared here but absent from `$on` simply has no subscriber — emitting it is a no-op
|
|
1307
|
+
|
|
1308
|
+
### `$on` — Receiving on the State Side
|
|
1309
|
+
|
|
1310
|
+
`$on` maps each event-token name to a handler. Because state is passed as the **first argument** (not via `this`), handlers can be written as either method shorthand or arrow functions — this mirrors the command-token emit convention, where `this` is likewise not bound:
|
|
1311
|
+
|
|
1312
|
+
```javascript
|
|
1313
|
+
$on: {
|
|
1314
|
+
// both forms work — state is always the first parameter
|
|
1315
|
+
userCreated: (state, event) => { state.lastId = event.detail.id; },
|
|
1316
|
+
rowFailed(state, event, ...listIndexes) {
|
|
1317
|
+
const [i] = listIndexes; // loop index when fired from inside a `for`
|
|
1318
|
+
state.failedRows = state.failedRows.concat(i);
|
|
1319
|
+
}
|
|
1320
|
+
}
|
|
1321
|
+
```
|
|
1322
|
+
|
|
1323
|
+
- Every `$on` key must be declared in `$eventTokens` (otherwise an error is thrown at initialization)
|
|
1324
|
+
- Each value must be a function
|
|
1325
|
+
- The signature is `(state, event, ...listIndexes)` — the DOM `Event` first, then any enclosing loop indexes
|
|
1326
|
+
|
|
1327
|
+
### `eventToken.<property>:` Binding
|
|
1328
|
+
|
|
1329
|
+
```html
|
|
1330
|
+
<my-target data-wcs="eventToken.error: createFailed"></my-target>
|
|
1331
|
+
```
|
|
1332
|
+
|
|
1333
|
+
| Part | Description |
|
|
1334
|
+
|---|---|
|
|
1335
|
+
| `eventToken.` | Fixed prefix |
|
|
1336
|
+
| `<property>` | A **wcBindable property name** — not a raw DOM event name. The real event name is resolved from `wcBindable.properties[].event` |
|
|
1337
|
+
| `<tokenName>` | A bare event-token name declared in `$eventTokens` (no `$`-namespace prefix, unlike command tokens) |
|
|
1338
|
+
|
|
1339
|
+
The key is a property name rather than a raw event name so the binding goes through the same `wcBindable` contract that command bindings use — and so a namespaced event name (`ns:evt`) cannot collide with the binding's `:` separator. The framework looks up `properties[].event` and attaches a listener for that real event:
|
|
1340
|
+
|
|
1341
|
+
```javascript
|
|
1342
|
+
class MyTarget extends HTMLElement {
|
|
1343
|
+
static wcBindable = {
|
|
1344
|
+
protocol: "wc-bindable", version: 1,
|
|
1345
|
+
properties: [
|
|
1346
|
+
{ name: "error", event: "thing-error" }, // eventToken.error → listens for "thing-error"
|
|
1347
|
+
{ name: "created", event: "thing-created" },
|
|
1348
|
+
],
|
|
1349
|
+
};
|
|
1350
|
+
}
|
|
1351
|
+
```
|
|
1352
|
+
|
|
1353
|
+
Validation rules:
|
|
1354
|
+
|
|
1355
|
+
- The element must be a wc-bindable custom element (`static wcBindable`, `protocol: "wc-bindable"`, `version: 1`). A non-wc-bindable element is rejected at attach time.
|
|
1356
|
+
- `<property>` must appear in `wcBindable.properties` — checked at **attach time** (fail-fast; needs only the class, not DOM connection).
|
|
1357
|
+
- `<tokenName>` must be declared in `$eventTokens` — checked at **fire time**. State is resolved from the element's live root node when the event fires, so the binding also works inside `for` / `if` blocks and after SSR hydration, where the node may still be detached at attach time.
|
|
1358
|
+
- Modifiers `#prevent` / `#stop` work as on any event binding: `eventToken.error#prevent: createFailed`.
|
|
1359
|
+
|
|
1360
|
+
### Inside a Loop
|
|
1361
|
+
|
|
1362
|
+
When the emitter sits inside a `for` block, the enclosing loop indexes are appended after the event, exactly like an `on*` handler:
|
|
1363
|
+
|
|
1364
|
+
```html
|
|
1365
|
+
<template data-wcs="for: rows">
|
|
1366
|
+
<my-row data-wcs="eventToken.failed: rowFailed"></my-row>
|
|
1367
|
+
</template>
|
|
1368
|
+
```
|
|
1369
|
+
|
|
1370
|
+
```javascript
|
|
1371
|
+
$on: {
|
|
1372
|
+
rowFailed(state, event, ...listIndexes) {
|
|
1373
|
+
const [i] = listIndexes; // index of the row that fired
|
|
1374
|
+
state.failedRows = state.failedRows.concat(i);
|
|
1375
|
+
}
|
|
1376
|
+
}
|
|
1377
|
+
```
|
|
1378
|
+
|
|
1379
|
+
### Fan-in and Chaining
|
|
1380
|
+
|
|
1381
|
+
Multiple elements can wire the same token (`eventToken.x: shared`) — every dispatch reaches the one `$on` handler, mirroring command-token fan-out. And because an `$on` handler receives `state`, it can re-emit a command token, chaining element → state → element:
|
|
1382
|
+
|
|
1383
|
+
```javascript
|
|
1384
|
+
$commandTokens: ["doRefresh"],
|
|
1385
|
+
$eventTokens: ["completed"],
|
|
1386
|
+
$on: {
|
|
1387
|
+
completed(state) {
|
|
1388
|
+
state.$command.doRefresh.emit(); // event in → command out
|
|
1389
|
+
}
|
|
1390
|
+
}
|
|
1391
|
+
```
|
|
1392
|
+
|
|
1393
|
+
### Token API
|
|
1394
|
+
|
|
1395
|
+
Event tokens share the same `Token` pub/sub primitive as command tokens — `name` / `size` / `subscribe` / `unsubscribe` / `emit`, with subscribe-order preservation (see [Token API](#token-api)). The token is resolved from the registry on every event so a re-`setInitialState()` rebuild still reaches the latest `$on` subscribers. When the owning `<wcs-state>` is disconnected, the event-token registry is cleared.
|
|
1396
|
+
|
|
1250
1397
|
## Inputs and Attribute Mirror
|
|
1251
1398
|
|
|
1252
1399
|
`wcBindable.inputs` declares one-way property inputs (state → element). When an entry sets `attribute`, the framework writes the value to that HTML attribute every time it writes the property, so `attributeChangedCallback`, CSS attribute selectors, and DevTools all stay in sync with the property value.
|
package/dist/index.esm.js
CHANGED
|
@@ -59,7 +59,7 @@ function setConfig(partialConfig) {
|
|
|
59
59
|
}
|
|
60
60
|
}
|
|
61
61
|
|
|
62
|
-
var version$1 = "1.
|
|
62
|
+
var version$1 = "1.13.0";
|
|
63
63
|
var pkg = {
|
|
64
64
|
version: version$1};
|
|
65
65
|
|
|
@@ -3469,6 +3469,21 @@ const SSR_ATTR_PROPS = {
|
|
|
3469
3469
|
},
|
|
3470
3470
|
};
|
|
3471
3471
|
function applyChangeToProperty(binding, _context, newValue) {
|
|
3472
|
+
// undefined は「状態が値を持たない=無意見」であり、書き込み自体をスキップして
|
|
3473
|
+
// 要素側の既定値を生かす。書き込んでしまうと setter の文字列化で
|
|
3474
|
+
// "undefined" 属性や removeAttribute が走り要素が壊れる (spread で未初期化
|
|
3475
|
+
// slot を配線したときに顕在化)。明示的なクリアは null で表現する。
|
|
3476
|
+
// mirror 属性 (applyMirrorAttribute) の「undefined → 属性削除」と同じ語彙。
|
|
3477
|
+
if (typeof newValue === "undefined") {
|
|
3478
|
+
if (config.debug) {
|
|
3479
|
+
console.debug(`Skipped property write: state value is undefined.`, {
|
|
3480
|
+
element: binding.node,
|
|
3481
|
+
propSegments: binding.propSegments,
|
|
3482
|
+
statePathName: binding.statePathName,
|
|
3483
|
+
});
|
|
3484
|
+
}
|
|
3485
|
+
return;
|
|
3486
|
+
}
|
|
3472
3487
|
const element = binding.node;
|
|
3473
3488
|
const propSegments = binding.propSegments;
|
|
3474
3489
|
if (propSegments.length === 1) {
|