@wcstack/raf 1.30.0 → 1.32.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 +14 -1
- package/README.md +14 -1
- package/dist/auto.min.js +1 -1
- package/dist/auto.min.js.map +1 -1
- package/dist/index.d.ts +40 -2
- package/dist/index.esm.js +145 -8
- package/dist/index.esm.js.map +1 -1
- package/package.json +1 -1
package/README.ja.md
CHANGED
|
@@ -83,9 +83,18 @@ npm install @wcstack/raf
|
|
|
83
83
|
| `once` | boolean | `false` | 1 フレームだけ発火して停止。`repeat="1"` の糖衣。 |
|
|
84
84
|
| `repeat` | number | `0` | N フレームで停止(`0` = 無制限)。`once` より優先。 |
|
|
85
85
|
| `manual` | boolean | `false` | 接続時に自動 start しない。コマンド / trigger で開始。 |
|
|
86
|
+
| `reduced-motion` | `"run"` \| `"pause"` | `"run"` | オプトインの `prefers-reduced-motion` ゲート。`"pause"` にすると、ユーザーの OS/ブラウザ設定が「動きを減らす」を要求している間はフレーム配送が止まり(`suspended` で観測可能)、解除されると `dt = 0` 境界で再開する。未知値は `"run"` に正規化。 |
|
|
86
87
|
|
|
87
88
|
`<wcs-timer>` から意図的に削除したもの: `interval`(rAF に周期は無い)と `immediate`(初回フレームがすでに「次の描画機会」であり、それより早い意味のある時点が存在しない)。
|
|
88
89
|
|
|
90
|
+
### `reduced-motion` の既定が `run` である理由
|
|
91
|
+
|
|
92
|
+
`<wcs-view-transition>` が既定でスキップを選べるのは、落とすものが装飾だけだから。`<wcs-raf>` の tick は**機能出力**(ゲームループ・計測・canvas シミュレーション)であり、既定で止めるのは修理ではなく意見になる(docs/a11y-design.md §0-1)。ループが「動きのための動き」を駆動しているときだけ `reduced-motion="pause"` でオプトインする。
|
|
93
|
+
|
|
94
|
+
### `pause()` の流用ではない理由
|
|
95
|
+
|
|
96
|
+
`pause()` は**ユーザー意図**の記録(`start()`/`stop()` がクリアし、`resume()` が上書きする)。reduced-motion ゲートは**環境条件**であり、混ぜると `resume()` が OS 設定を上書きできてしまう。そこでゲートは `suspended` の第二原因 — `suspended = running && (hidden || reducedGate)` — として、visibility と同じ形でモデル化した。preference はライブ購読(`observe()` が `change` リスナを張る): start 時チェックだけの実装では、reduce 中に開始したループが解除を検知する機会を永遠に持てない。
|
|
97
|
+
|
|
89
98
|
## 観測可能プロパティ(出力)
|
|
90
99
|
|
|
91
100
|
| プロパティ | イベント | 説明 |
|
|
@@ -94,7 +103,7 @@ npm install @wcstack/raf
|
|
|
94
103
|
| `elapsed` | `wcs-raf:tick` | 最後の reset からの**アクティブ**時間(Σdt、ms)。非表示・ポーズ期間は加算されない。粒度はフレーム単位。 |
|
|
95
104
|
| `dt` | `wcs-raf:tick` | 直前フレームとの差分(ms)。**`start()` / `resume()` / visibility 中断の直後の初回フレームは `0`** — 中断を跨いだ値は観測者に届かない。上限クランプは無し: 遅いフレームの扱いはドメイン判断(物理ループなら自前の `Math.min(dt, …)`)。 |
|
|
96
105
|
| `running` | `wcs-raf:running-changed` | 開始済みの**意図**。非表示タブでフレームが届かなくても `true` のまま。 |
|
|
97
|
-
| `suspended` | `wcs-raf:suspended-changed` |
|
|
106
|
+
| `suspended` | `wcs-raf:suspended-changed` | 配送の**実態**。原因は 2 つ: `running` かつ非表示タブ(rAF はスロットルでなく完全停止)、またはオプトインの `reduced-motion="pause"` ゲートがユーザー設定で効いている間。desired/actual の分離は `@wcstack/wakelock` の `active`/`held` と同型。 |
|
|
98
107
|
|
|
99
108
|
`tick` / `elapsed` / `dt` は単一の `wcs-raf:tick` イベントからの派生です(`detail = { count, elapsed, dt, timestamp }`。`timestamp` はフレームの `DOMHighResTimeStamp`、`reset()` 通知では `0`)。`tick` は同値ガード無しで毎フレーム発火、`running` / `suspended` は同値ガード付きです。
|
|
100
109
|
|
|
@@ -175,6 +184,10 @@ bootstrapRaf({
|
|
|
175
184
|
});
|
|
176
185
|
```
|
|
177
186
|
|
|
187
|
+
## アクセシビリティ
|
|
188
|
+
|
|
189
|
+
**WCAG 2.2.2 Pause, Stop, Hide(一時停止・停止・非表示)**: 見えるコンテンツを動かすフレームループには、ユーザーが使える一時停止が要る — 部品は揃っている: `pause` / `resume` / `stop` は第一級のコマンドなので、そこへ配線した可視のコントロール 1 つで基準を満たせる。動きのための動きには、上記のオプトイン `reduced-motion="pause"` ゲートも検討すること — ユーザーの OS 設定を自動で尊重する。
|
|
190
|
+
|
|
178
191
|
## ライセンス
|
|
179
192
|
|
|
180
193
|
MIT
|
package/README.md
CHANGED
|
@@ -83,9 +83,18 @@ Note: the auto-started `once` frame fires about one frame after connect, exactly
|
|
|
83
83
|
| `once` | boolean | `false` | Fire a single frame, then stop. Sugar for `repeat="1"`. |
|
|
84
84
|
| `repeat` | number | `0` | Stop after N frames (`0` = unlimited). Takes precedence over `once`. |
|
|
85
85
|
| `manual` | boolean | `false` | Do not auto-start on connect; start via command / trigger. |
|
|
86
|
+
| `reduced-motion` | `"run"` \| `"pause"` | `"run"` | Opt-in `prefers-reduced-motion` gate. With `"pause"`, frame delivery stops while the user's OS/browser preference requests reduced motion (surfaced via `suspended`), and resumes with a `dt = 0` boundary when it clears. Unknown values normalize to `"run"`. |
|
|
86
87
|
|
|
87
88
|
Deliberately absent vs `<wcs-timer>`: `interval` (rAF has no period) and `immediate` (the first frame already **is** the next rendering opportunity — no earlier meaningful moment exists).
|
|
88
89
|
|
|
90
|
+
### Why `reduced-motion` defaults to `run`
|
|
91
|
+
|
|
92
|
+
`<wcs-view-transition>` can default its `reduced-motion` handling to skipping because what it drops is decoration only. A `<wcs-raf>` tick is **functional output** — game loops, measurements, canvas simulations — so stopping it by default would be an opinion, not a repair (docs/a11y-design.md §0-1). Opt in with `reduced-motion="pause"` when your loop drives motion for motion's sake.
|
|
93
|
+
|
|
94
|
+
### Why it is not `pause()` reuse
|
|
95
|
+
|
|
96
|
+
`pause()` records **user intent** (`start()`/`stop()` clear it, `resume()` overrides it). The reduced-motion gate is an **environment condition**: mixing the two would let `resume()` override the user's OS setting. Instead the gate is a second cause of `suspended` — `suspended = running && (hidden || reducedGate)` — exactly the shape visibility already has. The preference is subscribed live (`change` listener, established by `observe()`): with a start-time check only, a loop started under reduced motion could never notice the preference clearing.
|
|
97
|
+
|
|
89
98
|
## Observable Properties (outputs)
|
|
90
99
|
|
|
91
100
|
| Property | Event | Description |
|
|
@@ -94,7 +103,7 @@ Deliberately absent vs `<wcs-timer>`: `interval` (rAF has no period) and `immedi
|
|
|
94
103
|
| `elapsed` | `wcs-raf:tick` | Accumulated **active** milliseconds (Σdt) since the last reset — hidden/paused periods contribute nothing. Frame-granular: between frames the getter returns the value as of the last tick. |
|
|
95
104
|
| `dt` | `wcs-raf:tick` | Delta to the previous frame in ms. **`0` on the first frame after `start()` / `resume()` / a visibility interruption** — a value spanning an interruption never reaches observers. No upper clamp: how to treat a slow frame is your domain decision (a physics loop typically applies its own `Math.min(dt, …)`). |
|
|
96
105
|
| `running` | `wcs-raf:running-changed` | The started **intent**: `true` from `start` until `stop`/`pause`/bounded completion. Stays `true` in a hidden tab even though no frames arrive. |
|
|
97
|
-
| `suspended` | `wcs-raf:suspended-changed` | The delivery **actuality
|
|
106
|
+
| `suspended` | `wcs-raf:suspended-changed` | The delivery **actuality**, with two causes: `true` while `running` in a hidden tab (rAF is fully stopped there — not throttled), or while the opt-in `reduced-motion="pause"` gate is engaged by the user's preference. The desired/actual split mirrors `@wcstack/wakelock`'s `active`/`held`. |
|
|
98
107
|
|
|
99
108
|
`tick` / `elapsed` / `dt` all derive from the single `wcs-raf:tick` event (`detail = { count, elapsed, dt, timestamp }`; `timestamp` is the frame's `DOMHighResTimeStamp`, `0` for the `reset()` notification). `tick` fires every frame with no equality guard; `running` / `suspended` are equality-guarded.
|
|
100
109
|
|
|
@@ -176,6 +185,10 @@ bootstrapRaf({
|
|
|
176
185
|
});
|
|
177
186
|
```
|
|
178
187
|
|
|
188
|
+
## Accessibility
|
|
189
|
+
|
|
190
|
+
**WCAG 2.2.2 Pause, Stop, Hide**: a frame loop that animates visible content needs a user-reachable pause — and the parts are already here: `pause` / `resume` / `stop` are first-class commands, so one visible control wired to them satisfies the criterion. For motion that exists for its own sake, also consider the opt-in [`reduced-motion="pause"`](#attributes--inputs) gate above, which honors the user's OS-level preference automatically.
|
|
191
|
+
|
|
179
192
|
## License
|
|
180
193
|
|
|
181
194
|
MIT
|
package/dist/auto.min.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
const t={triggerAttribute:"data-raftarget",tagNames:{raf:"wcs-raf"}};class e extends EventTarget{static wcBindable={protocol:"wc-bindable",version:1,properties:[{name:"tick",event:"wcs-raf:tick",semantics:"state",getter:t=>t.detail.count},{name:"elapsed",event:"wcs-raf:tick",semantics:"state",getter:t=>t.detail.elapsed},{name:"dt",event:"wcs-raf:tick",semantics:"state",getter:t=>t.detail.dt},{name:"running",event:"wcs-raf:running-changed",semantics:"state"},{name:"suspended",event:"wcs-raf:suspended-changed",semantics:"state"}],commands:[{name:"start"},{name:"stop"},{name:"reset"},{name:"pause"},{name:"resume"}]};_target;_injectedScheduler;_handle=null;_globalScheduler=null;_gen=0;_ready=Promise.resolve();_tick=0;_dt=0;_elapsed=0;_running=!1;_suspended=!1;_paused=!1;_lastTs=null;_repeat=0;_runStartTick=0;_visibilityDoc=null;constructor(t,e){super(),this._target=t??this,this._injectedScheduler=e??null}get tick(){return this._tick}get elapsed(){return this._elapsed}get dt(){return this._dt}get running(){return this._running}get suspended(){return this._suspended}get ready(){return this._ready}observe(){
|
|
1
|
+
const t={triggerAttribute:"data-raftarget",tagNames:{raf:"wcs-raf"}};class e extends EventTarget{static wcBindable={protocol:"wc-bindable",version:1,properties:[{name:"tick",event:"wcs-raf:tick",semantics:"state",getter:t=>t.detail.count},{name:"elapsed",event:"wcs-raf:tick",semantics:"state",getter:t=>t.detail.elapsed},{name:"dt",event:"wcs-raf:tick",semantics:"state",getter:t=>t.detail.dt},{name:"running",event:"wcs-raf:running-changed",semantics:"state"},{name:"suspended",event:"wcs-raf:suspended-changed",semantics:"state"}],commands:[{name:"start"},{name:"stop"},{name:"reset"},{name:"pause"},{name:"resume"}]};_target;_injectedScheduler;_handle=null;_globalScheduler=null;_gen=0;_ready=Promise.resolve();_tick=0;_dt=0;_elapsed=0;_running=!1;_suspended=!1;_paused=!1;_lastTs=null;_repeat=0;_runStartTick=0;_visibilityDoc=null;_reducedMotion="run";_mql=null;_injectedMatchMedia;constructor(t,e,s){super(),this._target=t??this,this._injectedScheduler=e??null,this._injectedMatchMedia=s??null}get tick(){return this._tick}get elapsed(){return this._elapsed}get dt(){return this._dt}get running(){return this._running}get suspended(){return this._suspended}get reducedMotion(){return this._reducedMotion}set reducedMotion(t){this._reducedMotion!==t&&(this._reducedMotion=t,this._applyReducedGate())}get ready(){return this._ready}observe(){if(null===this._visibilityDoc&&"undefined"!=typeof document&&(this._visibilityDoc=document,document.addEventListener("visibilitychange",this._onVisibilityChange),this._updateSuspended()),null===this._mql){const t=this._resolveMatchMedia();if(null!==t)try{const e=t("(prefers-reduced-motion: reduce)");e.addEventListener("change",this._onReducedMotionChange),this._mql=e,this._applyReducedGate()}catch{this._mql=null}}return this._ready}dispose(){this._gen++,this.stop(),null!==this._visibilityDoc&&(this._visibilityDoc.removeEventListener("visibilitychange",this._onVisibilityChange),this._visibilityDoc=null),null!==this._mql&&(this._mql.removeEventListener("change",this._onReducedMotionChange),this._mql=null)}_dispatchTick(t){this._target.dispatchEvent(new CustomEvent("wcs-raf:tick",{detail:{count:this._tick,elapsed:this._elapsed,dt:this._dt,timestamp:t},bubbles:!0}))}_setRunning(t){this._running!==t&&(this._running=t,this._target.dispatchEvent(new CustomEvent("wcs-raf:running-changed",{detail:t,bubbles:!0})),this._updateSuspended())}_setSuspended(t){this._suspended!==t&&(this._suspended=t,this._target.dispatchEvent(new CustomEvent("wcs-raf:suspended-changed",{detail:t,bubbles:!0})))}_updateSuspended(){const t=null!==this._visibilityDoc&&"hidden"===this._visibilityDoc.visibilityState;this._setSuspended(this._running&&(t||this._reducedGate()))}_reducedGate(){return"pause"===this._reducedMotion&&null!==this._mql&&this._mql.matches}_onReducedMotionChange=()=>{this._applyReducedGate()};_applyReducedGate(){if(this._running)if(this._reducedGate())this._clearHandle();else if(null===this._handle){this._lastTs=null;const t=this._resolveScheduler();null!==t&&this._requestFrame(t)}this._updateSuspended()}start(t={}){if(this._running)return;const e=this._resolveScheduler();null!==e&&(this._paused=!1,this._repeat="number"==typeof t.repeat&&t.repeat>0?t.repeat:0,this._gen++,this._setRunning(!0),this._runStartTick=this._tick,this._lastTs=null,this._running&&null===this._handle&&(this._reducedGate()||this._requestFrame(e)))}stop(){this._clearHandle(),this._paused=!1,this._setRunning(!1)}reset(){this._clearHandle(),this._paused=!1,this._tick=0,this._elapsed=0,this._dt=0,this._lastTs=null,this._setRunning(!1),this._dispatchTick(0)}pause(){this._running&&!this._paused&&(this._clearHandle(),this._paused=!0,this._setRunning(!1))}resume(){if(!this._paused)return;const t=this._resolveScheduler();null!==t&&(this._paused=!1,this._gen++,this._setRunning(!0),this._lastTs=null,this._running&&null===this._handle&&(this._reducedGate()||this._requestFrame(t)))}_frame=t=>{this._handle=null;const e=null===this._lastTs?0:t-this._lastTs;if(this._lastTs=t,this._tick++,this._dt=e,this._elapsed+=e,this._dispatchTick(t),this._repeat>0&&this._tick-this._runStartTick>=this._repeat)return this._clearHandle(),this._paused=!1,void this._setRunning(!1);if(this._running&&null===this._handle&&!this._reducedGate()){const t=this._resolveScheduler();null!==t&&this._requestFrame(t)}};_onVisibilityChange=()=>{this._lastTs=null,this._updateSuspended()};_resolveScheduler(){if(null!==this._injectedScheduler)return this._injectedScheduler;const t=globalThis;return"function"!=typeof t.requestAnimationFrame||"function"!=typeof t.cancelAnimationFrame?null:(null===this._globalScheduler&&(this._globalScheduler={request:e=>t.requestAnimationFrame(e),cancel:e=>t.cancelAnimationFrame(e)}),this._globalScheduler)}_resolveMatchMedia(){if(null!==this._injectedMatchMedia)return this._injectedMatchMedia;const t=globalThis;return"function"!=typeof t.matchMedia?null:e=>t.matchMedia(e)}_requestFrame(t){const e=this._gen;this._handle=t.request(t=>{e===this._gen&&this._frame(t)})}_clearHandle(){null!==this._handle&&(this._resolveScheduler()?.cancel(this._handle),this._handle=null,this._gen++)}}let s=!1;function i(e){const s=e.target;if(!(s instanceof Element))return;const i=s.closest(`[${t.triggerAttribute}]`);if(!i)return;const n=i.getAttribute(t.triggerAttribute);if(!n)return;const r=customElements.get(t.tagNames.raf),a=document.getElementById(n);r&&a instanceof r&&(e.preventDefault(),a.start())}function n(t,e){let s=Object.getPrototypeOf(t);for(;null!==s;){const t=Object.getOwnPropertyDescriptor(s,e);if(void 0!==t)return"function"==typeof t.get||"function"==typeof t.set;s=Object.getPrototypeOf(s)}return!1}class r extends HTMLElement{static hasConnectedCallbackPromise=!0;static wcBindable={...e.wcBindable,properties:[...e.wcBindable.properties,{name:"trigger",event:"wcs-raf:trigger-changed",semantics:"state"}],inputs:[{name:"once",attribute:"once"},{name:"repeat",attribute:"repeat"},{name:"manual",attribute:"manual"},{name:"reducedMotion",attribute:"reduced-motion"},{name:"trigger"}]};static get observedAttributes(){return["reduced-motion"]}_core;_trigger=!1;_connectedCallbackPromise=Promise.resolve();_internals=null;constructor(){super(),this._core=new e(this),this._internals=this._initInternals(),this._wireStates({"wcs-raf:running-changed":t=>({running:!0===t}),"wcs-raf:suspended-changed":t=>({suspended:!0===t})})}get debugStates(){return this._internals?[...this._internals.states]:[]}_initInternals(){try{if("function"!=typeof this.attachInternals)return null;const t=this.attachInternals();return t.states.add("wcs-probe"),t.states.delete("wcs-probe"),t}catch{return null}}_wireStates(t){if(null===this._internals)return;const e=this._internals.states;for(const[s,i]of Object.entries(t))this.addEventListener(s,t=>{const s=this.hasAttribute("debug-states");for(const[n,r]of Object.entries(i(t.detail))){try{r?e.add(n):e.delete(n)}catch{}s&&this.toggleAttribute(`data-wcs-state-${n}`,r)}})}get connectedCallbackPromise(){return this._connectedCallbackPromise}get once(){return this.hasAttribute("once")}set once(t){t?this.setAttribute("once",""):this.removeAttribute("once")}get repeat(){const t=this.getAttribute("repeat");if(null===t||""===t.trim())return 0;const e=Number(t);return Number.isFinite(e)&&e>0?e:0}set repeat(t){this.setAttribute("repeat",String(t))}get manual(){return this.hasAttribute("manual")}set manual(t){t?this.setAttribute("manual",""):this.removeAttribute("manual")}get reducedMotion(){return this._core.reducedMotion}set reducedMotion(t){this.setAttribute("reduced-motion",t)}attributeChangedCallback(t,e,s){"reduced-motion"===t&&(this._core.reducedMotion="pause"===s?"pause":"run")}get tick(){return this._core.tick}get elapsed(){return this._core.elapsed}get dt(){return this._core.dt}get running(){return this._core.running}get suspended(){return this._core.suspended}get trigger(){return this._trigger}set trigger(t){!!t&&(this._trigger=!0,this.start(),this._trigger=!1,this.dispatchEvent(new CustomEvent("wcs-raf:trigger-changed",{detail:!1,bubbles:!0})))}start(){const t=this.repeat>0?this.repeat:this.once?1:0;this._core.start({repeat:t})}stop(){this._core.stop()}reset(){this._core.reset()}pause(){this._core.pause()}resume(){this._core.resume()}connectedCallback(){!function(t){const e=t.constructor?.wcBindable,s=e?.inputs;if(void 0!==s)for(const e of s){const s=e.name;if(!Object.prototype.hasOwnProperty.call(t,s))continue;if(!n(t,s))continue;const i=t,r=i[s];delete i[s],i[s]=r}}(this),this.style.display="none",s||(s=!0,document.addEventListener("click",i)),this._connectedCallbackPromise=this._core.observe(),this.manual||this.start()}disconnectedCallback(){this._core.dispose()}}var a;!function(e=customElements){e.get(t.tagNames.raf)||e.define(t.tagNames.raf,r)}(a);
|
|
2
2
|
//# sourceMappingURL=auto.min.js.map
|
package/dist/auto.min.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"auto.min.js","sources":["../src/config.ts","../src/core/RafCore.ts","../src/autoTrigger.ts","../src/protocol/upgradeProperties.ts","../src/components/Raf.ts","../src/registerComponents.ts"],"sourcesContent":["import { IConfig, IWritableConfig } from \"./types.js\";\n\ninterface IInternalConfig extends IConfig {\n autoTrigger: boolean;\n triggerAttribute: string;\n tagNames: {\n raf: string;\n };\n}\n\nconst _config: IInternalConfig = {\n autoTrigger: true,\n triggerAttribute: \"data-raftarget\",\n tagNames: {\n raf: \"wcs-raf\",\n },\n};\n\nfunction deepFreeze<T>(obj: T): T {\n if (obj === null || typeof obj !== \"object\") return obj;\n Object.freeze(obj);\n for (const key of Object.keys(obj)) {\n deepFreeze((obj as Record<string, unknown>)[key]);\n }\n return obj;\n}\n\nfunction deepClone<T>(obj: T): T {\n if (obj === null || typeof obj !== \"object\") return obj;\n const clone: Record<string, unknown> = {};\n for (const key of Object.keys(obj)) {\n clone[key] = deepClone((obj as Record<string, unknown>)[key]);\n }\n return clone as T;\n}\n\nlet frozenConfig: IConfig | null = null;\n\n// Internal-only live handle to the mutable config. NOT part of the public API\n// (deliberately absent from exports.ts) — it is exported solely so sibling\n// modules in this package can read current settings cheaply. External consumers\n// must use getConfig() (returns a deep-frozen snapshot) / setConfig(). Mutating\n// this object directly bypasses the frozenConfig cache and is unsupported.\nexport const config: IConfig = _config as IConfig;\n\nexport function getConfig(): IConfig {\n if (!frozenConfig) {\n frozenConfig = deepFreeze(deepClone(_config));\n }\n return frozenConfig;\n}\n\nexport function setConfig(partialConfig: IWritableConfig): void {\n if (typeof partialConfig.autoTrigger === \"boolean\") {\n _config.autoTrigger = partialConfig.autoTrigger;\n }\n if (typeof partialConfig.triggerAttribute === \"string\") {\n _config.triggerAttribute = partialConfig.triggerAttribute;\n }\n if (partialConfig.tagNames) {\n Object.assign(_config.tagNames, partialConfig.tagNames);\n }\n frozenConfig = null;\n}\n","import { IWcBindable } from \"../types.js\";\n\nexport interface RafStartOptions {\n repeat?: number;\n}\n\n/**\n * Injectable frame scheduler. The default resolves\n * `globalThis.requestAnimationFrame` / `cancelAnimationFrame` AT CALL TIME\n * (async-io-node-guidelines §3.7); tests inject a fake that pumps frames with\n * explicit timestamps (the `dt` contract is timestamp-derived, so tests must\n * control the clock, not just the callback order).\n *\n * Contract: `request()` MUST return a non-null handle. The core uses `null`\n * as its internal \"not armed\" sentinel, so a scheduler returning literal\n * `null` would silently corrupt the handle bookkeeping (re-entrancy guards\n * and cancel tracking). Native rAF returns a long, so this only concerns\n * custom scheduler injections — return a number, object, or any other\n * non-nullish token.\n */\nexport interface RafScheduler {\n request(callback: (timestamp: number) => void): unknown;\n cancel(handle: unknown): void;\n}\n\n/**\n * Headless requestAnimationFrame primitive — `TimerCore`'s sibling with the\n * time source swapped from `setInterval` (a period) to rAF (the browser's\n * rendering opportunity). Exposed through the wc-bindable protocol: it streams\n * `tick` (frame counter), `elapsed` (accumulated ACTIVE milliseconds), `dt`\n * (delta to the previous frame) and the `running` / `suspended` pair, and is\n * driven by the `start` / `stop` / `reset` / `pause` / `resume` commands.\n *\n * `tick` / `elapsed` / `dt` are all surfaced via the single `wcs-raf:tick`\n * event (read through getters, mirroring how FetchCore exposes value/status\n * from one `wcs-fetch:response` event).\n *\n * Contracts specific to this node (docs/raf-tag-design.md):\n *\n * - **dt describes continuous running only.** The first frame after `start()`,\n * `resume()`, or a visibility interruption reports `dt = 0` — a value that\n * spans an interruption never reaches observers. Like `suspended`, the\n * visibility boundary is only detected once observe() has subscribed to\n * `visibilitychange`; a headless setup that skips observe() will see the\n * raw spanning delta on the first frame after a hidden gap. There is\n * deliberately NO upper clamp: how to treat a slow frame is the consumer's\n * domain decision.\n * - **elapsed is Σdt (active time).** Because interruption-spanning deltas are\n * normalized to 0, summing dt yields exactly the time frames were actually\n * being delivered — no separate segment bookkeeping is needed, and hidden /\n * paused periods contribute nothing. Granularity is one frame: between\n * frames the getter returns the value as of the last tick.\n * - **running / suspended are a desired/actual pair** (the wakelock split): in\n * a hidden tab the browser delivers no frames at all, so `running` (the\n * started intent) stays true while `suspended` reports that delivery is\n * actually stopped. `suspended` is only meaningful after `observe()` has\n * subscribed to `visibilitychange`; without a document it stays false.\n * - **No `error` surface.** rAF has no persistent failure mode; on a platform\n * without it, `start()` is a silent no-op (never-throw, resize precedent).\n */\nexport class RafCore extends EventTarget {\n static wcBindable: IWcBindable = {\n protocol: \"wc-bindable\",\n version: 1,\n properties: [\n { name: \"tick\", event: \"wcs-raf:tick\", semantics: \"state\", getter: (e: Event) => (e as CustomEvent).detail.count },\n { name: \"elapsed\", event: \"wcs-raf:tick\", semantics: \"state\", getter: (e: Event) => (e as CustomEvent).detail.elapsed },\n { name: \"dt\", event: \"wcs-raf:tick\", semantics: \"state\", getter: (e: Event) => (e as CustomEvent).detail.dt },\n { name: \"running\", event: \"wcs-raf:running-changed\", semantics: \"state\" },\n { name: \"suspended\", event: \"wcs-raf:suspended-changed\", semantics: \"state\" },\n ],\n commands: [\n { name: \"start\" },\n { name: \"stop\" },\n { name: \"reset\" },\n { name: \"pause\" },\n { name: \"resume\" },\n ],\n };\n\n private _target: EventTarget;\n private _injectedScheduler: RafScheduler | null;\n private _handle: unknown = null;\n\n // Lazily-created wrapper around the global rAF pair, cached so the hot\n // frame-reschedule path (_frame, once per delivered frame) does not\n // allocate a new object + closures every call. `request`/`cancel` still\n // dereference `globalThis.requestAnimationFrame` / `cancelAnimationFrame`\n // live on every invocation (they are not snapshotted here), so call-time\n // resolution (§3.7) is unchanged — only the wrapper object itself is\n // reused once the global functions are first found present.\n private _globalScheduler: RafScheduler | null = null;\n\n // Generation guard (§3.4): a monotonic arming counter. Bumped when a run is\n // armed (start()/resume()), when an armed handle is cancelled\n // (_clearHandle()) and on dispose(). _requestFrame() captures the value in\n // each request's closure and drops the frame if it no longer matches the\n // live field when it fires. cancel() is best-effort against a non-compliant\n // scheduler; the captured generation is the guarantee — a stale callback can\n // neither mutate state, dispatch on a torn-down element, nor corrupt a\n // newer run's `_handle` bookkeeping. A live-field comparison (the previous\n // `_runGen` scheme) could not survive a dispose() → start() round trip: the\n // new start() re-synced the pair and let the stale callback through,\n // permanently doubling the frame loop.\n private _gen = 0;\n // SSR (§3.8): there is no asynchronous probe, so readiness is immediate.\n private _ready: Promise<void> = Promise.resolve();\n\n private _tick: number = 0;\n private _dt: number = 0;\n private _elapsed: number = 0;\n private _running: boolean = false;\n private _suspended: boolean = false;\n private _paused: boolean = false;\n\n // Timestamp of the previous frame within the current continuous run.\n // `null` means \"the next frame starts a run segment\": its dt is reported as\n // 0 (the G3 normalization). Cleared at start()/resume() and on every\n // visibilitychange (an interruption boundary).\n private _lastTs: number | null = null;\n\n // `_tick` value captured at the start of the current run. `repeat` counts\n // frames *per run*, so the stop condition compares against this baseline\n // rather than the cumulative `_tick` (which only resets on reset()).\n private _repeat: number = 0;\n private _runStartTick: number = 0;\n\n // The document whose visibility drives `suspended`, subscribed in observe()\n // and released in dispose(). Null before observe() or in non-DOM\n // environments — `suspended` then simply stays false.\n private _visibilityDoc: Document | null = null;\n\n constructor(target?: EventTarget, scheduler?: RafScheduler) {\n super();\n this._target = target ?? this;\n this._injectedScheduler = scheduler ?? null;\n }\n\n get tick(): number {\n return this._tick;\n }\n\n get elapsed(): number {\n return this._elapsed;\n }\n\n get dt(): number {\n return this._dt;\n }\n\n get running(): boolean {\n return this._running;\n }\n\n get suspended(): boolean {\n return this._suspended;\n }\n\n // SSR readiness (§3.8): resolves after the first probe. There is nothing to\n // probe, so this is an already-resolved promise.\n get ready(): Promise<void> {\n return this._ready;\n }\n\n // Lifecycle (§3.5). observe() establishes the one ambient subscription this\n // node has — `visibilitychange`, which drives the `suspended` output and the\n // dt=0 normalization across a hidden period. Idempotent; a no-op without a\n // document (SSR pre-pass, worker). dispose() tears everything down and bumps\n // the generation so a frame already queued cannot fire onto a torn-down\n // element.\n observe(): Promise<void> {\n if (this._visibilityDoc === null && typeof document !== \"undefined\") {\n this._visibilityDoc = document;\n document.addEventListener(\"visibilitychange\", this._onVisibilityChange);\n // Sync `suspended` to the visibility state at subscription time: with a\n // start()-before-observe() ordering (headless Core usage) the document\n // may already be hidden, and waiting for the next visibilitychange\n // would report suspended=false until then. Same-value guarded, so the\n // common visible-at-observe case dispatches nothing.\n this._updateSuspended();\n }\n return this._ready;\n }\n\n dispose(): void {\n this._gen++;\n this.stop();\n if (this._visibilityDoc !== null) {\n this._visibilityDoc.removeEventListener(\"visibilitychange\", this._onVisibilityChange);\n this._visibilityDoc = null;\n }\n }\n\n // --- State setters with event dispatch ---\n\n private _dispatchTick(timestamp: number): void {\n this._target.dispatchEvent(new CustomEvent(\"wcs-raf:tick\", {\n detail: { count: this._tick, elapsed: this._elapsed, dt: this._dt, timestamp },\n bubbles: true,\n }));\n }\n\n private _setRunning(running: boolean): void {\n if (this._running === running) return;\n this._running = running;\n this._target.dispatchEvent(new CustomEvent(\"wcs-raf:running-changed\", {\n detail: running,\n bubbles: true,\n }));\n // `suspended` is derived from (running && hidden), so every running\n // transition re-evaluates it: stop/pause drop a suspension, and a start()\n // inside an already-hidden tab reports it immediately (honestly: no frame\n // will arrive until the tab is visible again).\n this._updateSuspended();\n }\n\n private _setSuspended(suspended: boolean): void {\n if (this._suspended === suspended) return;\n this._suspended = suspended;\n this._target.dispatchEvent(new CustomEvent(\"wcs-raf:suspended-changed\", {\n detail: suspended,\n bubbles: true,\n }));\n }\n\n private _updateSuspended(): void {\n const hidden = this._visibilityDoc !== null && this._visibilityDoc.visibilityState === \"hidden\";\n this._setSuspended(this._running && hidden);\n }\n\n // --- Public API ---\n\n start(options: RafStartOptions = {}): void {\n // Idempotent while running: a redundant start() must not stack a second\n // frame loop (which would double the tick rate). Reconfiguring an active\n // run is done via stop() + start().\n if (this._running) return;\n\n // Resolve the platform API at call time (§3.7). Absent rAF (SSR pre-pass,\n // worker) makes start() a silent no-op — never-throw, and this node has no\n // error surface by design.\n const scheduler = this._resolveScheduler();\n if (scheduler === null) return;\n\n // start() begins a fresh run, so clear any lingering pause from a prior\n // pause()-without-resume(). Without this, the loop would run while _paused\n // stayed true, leaving pause() a no-op and letting resume() overwrite the\n // live handle (leak + double fire).\n this._paused = false;\n\n // `repeat` is per-run intent, NOT persistent configuration: every start()\n // re-establishes it from the options, defaulting to \"unlimited\" when\n // omitted. This keeps a bare start() after a bounded run from silently\n // inheriting the old bounds.\n this._repeat = (typeof options.repeat === \"number\" && options.repeat > 0) ? options.repeat : 0;\n\n // New arming generation (§3.4): invalidates any callback still in flight\n // from a previous run (e.g. one whose cancel() a non-compliant scheduler\n // ignored). Bumped BEFORE the running-changed dispatch below, so that a\n // re-entrant restart from a listener arms with the newest generation —\n // the re-entrancy guard then keeps this outer call from arming (and\n // bumping) on top of it.\n this._gen++;\n\n this._setRunning(true);\n // Baseline this run's per-run repeat counting (set after _setRunning so a\n // re-start of a completed bounded run fires the full N frames again).\n this._runStartTick = this._tick;\n // G3: the first frame of a run reports dt = 0.\n this._lastTs = null;\n\n // Re-entrancy guard: _setRunning(true) just dispatched running-changed\n // synchronously, and a listener may have changed the world from inside it.\n // - `!_running`: the listener called stop()/pause()/dispose(). Without\n // this check a \"ghost\" frame would still be scheduled for an\n // already-stopped run — it would either tick once while running stays\n // false, or leave an uncancellable handle behind.\n // - `_handle !== null`: the listener restarted the loop itself\n // (stop()→start()); the inner start() already armed the new run, and\n // requesting again here would overwrite `_handle` (losing the inner\n // handle, never cancelled) and stack a permanent second frame loop.\n // On the normal path `_handle` is always null here — every transition\n // to `_running === false` clears it — so non-null can only mean a\n // re-entrant listener already scheduled the run for us.\n if (!this._running || this._handle !== null) return;\n this._requestFrame(scheduler);\n }\n\n stop(): void {\n this._clearHandle();\n this._paused = false;\n this._setRunning(false);\n }\n\n reset(): void {\n this._clearHandle();\n this._paused = false;\n this._tick = 0;\n this._elapsed = 0;\n this._dt = 0;\n this._lastTs = null;\n this._setRunning(false);\n // Notify observers that the counter/elapsed/dt have returned to zero. The\n // notification is not a frame, so `timestamp` is 0 (see WcsRafTickDetail).\n this._dispatchTick(0);\n }\n\n pause(): void {\n // Pause only a live loop; a no-op otherwise so it composes safely with the\n // declarative lifecycle. Unlike stop(), it records `_paused` so resume()\n // can tell an intentional pause from a full stop. No elapsed bookkeeping\n // is needed: elapsed is Σdt, and the resume boundary's dt is 0.\n if (!this._running || this._paused) return;\n this._clearHandle();\n this._paused = true;\n this._setRunning(false);\n }\n\n resume(): void {\n if (!this._paused) return;\n const scheduler = this._resolveScheduler();\n if (scheduler === null) return;\n this._paused = false;\n // New arming generation (§3.4), bumped before the running-changed\n // dispatch for the same re-entrancy reason as start().\n this._gen++;\n this._setRunning(true);\n // G3: the first frame after a pause reports dt = 0 (elapsed therefore does\n // not count the paused period — the \"active time\" contract).\n this._lastTs = null;\n\n // Re-entrancy guard, for the same reasons as start() (see the comment\n // there): a running-changed listener may have synchronously stopped this\n // node — or restarted it, leaving `_handle` already armed — from inside\n // _setRunning(true) above.\n if (!this._running || this._handle !== null) return;\n this._requestFrame(scheduler);\n }\n\n // --- Internal ---\n\n private _frame = (timestamp: number): void => {\n // Reached only through _requestFrame's generation-checked closure (§3.4):\n // a stale callback — disposed, cancelled by a non-compliant scheduler, or\n // superseded by a newer run — never gets here.\n this._handle = null;\n\n // dt: delta to the previous frame within this continuous run; 0 when this\n // frame opens a segment (start/resume/visibility boundary — G3).\n const dt = this._lastTs === null ? 0 : timestamp - this._lastTs;\n this._lastTs = timestamp;\n\n this._tick++;\n this._dt = dt;\n this._elapsed += dt;\n this._dispatchTick(timestamp);\n\n // Auto-stop once this run has fired the requested number of frames\n // (repeat=0 runs forever). Counted per-run via `_runStartTick`, so a\n // re-start after a completed bounded run fires N frames again. `once` is\n // expressed by the Shell as repeat=1.\n //\n // The cleanup mirrors stop() exactly, because a tick listener may have\n // synchronously paused — or paused and resumed — DURING the final frame's\n // dispatch above. The run's budget is exhausted either way, so clear the\n // pause (a later resume() must be a no-op, not an N+1th frame) and cancel\n // any handle a re-entrant resume() armed (it would otherwise survive as a\n // ghost frame and tick past the budget). On the normal path both are\n // already clear (no-ops). A stop()→start() restart is NOT affected: the\n // new run re-baselines `_runStartTick`, so this branch is not taken.\n if (this._repeat > 0 && (this._tick - this._runStartTick) >= this._repeat) {\n this._clearHandle();\n this._paused = false;\n this._setRunning(false);\n return;\n }\n\n // Re-request the next frame — unless a tick listener stopped the loop\n // synchronously during the dispatch above, or already scheduled a new run\n // itself (a synchronous stop()→start() / pause()→resume() restart leaves\n // _handle non-null; re-requesting on top of it would stack a permanent\n // second frame loop. The generation guard cannot catch this: a tail\n // request here would capture the restart's own — current — generation\n // and produce a second equally-valid loop).\n if (this._running && this._handle === null) {\n const scheduler = this._resolveScheduler();\n if (scheduler !== null) {\n this._requestFrame(scheduler);\n }\n }\n };\n\n private _onVisibilityChange = (): void => {\n // Either direction is an interruption boundary: entering hidden means the\n // browser stops delivering frames, so the NEXT delivered frame must not\n // report a delta spanning the gap (G3). Clearing on the visible edge too\n // is belt-and-braces for a missed hidden event — the worst case is one\n // extra dt=0 frame.\n this._lastTs = null;\n this._updateSuspended();\n };\n\n private _resolveScheduler(): RafScheduler | null {\n if (this._injectedScheduler !== null) return this._injectedScheduler;\n const g = globalThis as unknown as {\n requestAnimationFrame?: (cb: (ts: number) => void) => unknown;\n cancelAnimationFrame?: (handle: unknown) => void;\n };\n // The availability check itself still runs on every call (§3.7: resolved\n // at call time, not cached across an absence/presence flip).\n if (typeof g.requestAnimationFrame !== \"function\" || typeof g.cancelAnimationFrame !== \"function\") {\n return null;\n }\n if (this._globalScheduler === null) {\n // `g` is just a typed alias for `globalThis` (not a snapshot), so these\n // closures keep dereferencing the live global functions even though the\n // wrapper object itself is created only once.\n this._globalScheduler = {\n request: (cb) => g.requestAnimationFrame!(cb),\n cancel: (handle) => g.cancelAnimationFrame!(handle),\n };\n }\n return this._globalScheduler;\n }\n\n // Arm the next frame (§3.4). The callback closes over the generation\n // current at request time and re-checks it against the live `_gen` when the\n // frame arrives; a callback that outlived its run bails here. See the\n // `_gen` field comment for why this must be a per-request capture and not a\n // live-field comparison.\n private _requestFrame(scheduler: RafScheduler): void {\n const gen = this._gen;\n this._handle = scheduler.request((timestamp: number) => {\n if (gen !== this._gen) return;\n this._frame(timestamp);\n });\n }\n\n private _clearHandle(): void {\n if (this._handle !== null) {\n this._resolveScheduler()?.cancel(this._handle);\n this._handle = null;\n // Invalidate the cancelled callback's captured generation as well:\n // cancel() is best-effort against a non-compliant scheduler, the\n // generation is the guarantee (§3.4).\n this._gen++;\n }\n }\n}\n","import { config } from \"./config.js\";\nimport type { Raf } from \"./components/Raf.js\";\n\nlet registered = false;\n\nfunction handleClick(event: Event): void {\n const target = event.target;\n if (!(target instanceof Element)) return;\n\n const triggerElement = target.closest<Element>(`[${config.triggerAttribute}]`);\n if (!triggerElement) return;\n\n const rafId = triggerElement.getAttribute(config.triggerAttribute);\n if (!rafId) return;\n\n // Resolve the registered constructor at call time instead of importing Raf\n // as a value. The value import created a components/Raf.ts ⇄ autoTrigger.ts\n // cycle (Raf.connectedCallback() calls registerAutoTrigger()). instanceof\n // against the customElements registry keeps the exact same identity guarantee\n // — only the registered <wcs-raf> class matches — without the import cycle.\n const RafCtor = customElements.get(config.tagNames.raf);\n const rafElement = document.getElementById(rafId);\n if (!RafCtor || !(rafElement instanceof RafCtor)) return;\n\n // Suppress the element's default action so a loop can start without\n // navigating. Intentional: do not attach data-raftarget to an element whose\n // default action you also want (real <a href> link, form-submit button) — it\n // will be cancelled. See README \"Optional DOM Triggering\".\n event.preventDefault();\n (rafElement as Raf).start();\n}\n\nexport function registerAutoTrigger(): void {\n if (registered) return;\n registered = true;\n document.addEventListener(\"click\", handleClick);\n}\n\nexport function unregisterAutoTrigger(): void {\n if (!registered) return;\n registered = false;\n document.removeEventListener(\"click\", handleClick);\n}\n","// ===========================================================================\n// AUTO-GENERATED FILE - DO NOT EDIT.\n// Generated from /protocol/upgrade-properties.ts by scripts/sync-protocol-types.mjs.\n// Run `node scripts/sync-protocol-types.mjs` after editing the source.\n// ===========================================================================\n\n// custom element の property upgrade — `static wcBindable.inputs` に宣言した入力のうち、\n// 要素が upgrade される前に代入された own データプロパティを取り込み直す。\n//\n// なぜ必要か:\n// 未定義タグの要素は素の HTMLElement なので、`el.url = \"...\"` は own データプロパティを作る。\n// upgrade 後にクラスの accessor が prototype へ入っても own プロパティが優先されるため、\n// setter は二度と呼ばれず、値は要素へ届かないまま消える(エラーも警告も出ない)。\n// 常にプロパティ代入を行う framework(Angular の `[prop]`、Lit の `.prop=`、\n// Solid の `prop:`、Vue の `.prop` 修飾子)× 遅延定義(autoloader / CDN / code-split)で\n// 常態的に起きる。docs/architecture-hardening/13-framework-adapter-binding-constraints.md §1.2。\n//\n// 安全側の判定:\n// own プロパティがあっても、prototype チェーンに accessor が無ければ「シャドウ」ではなく\n// その own プロパティ自体が正規の格納先なので触らない(public class field を壊さない)。\n//\n// SINGLE SOURCE OF TRUTH: edit only this file (/protocol/upgrade-properties.ts), then run\n// `node scripts/sync-protocol-types.mjs` to regenerate the per-package copies\n// (packages/<pkg>/src/protocol/upgradeProperties.ts). Those copies are generated — do not edit them.\nimport { IWcBindable } from \"./wcBindable.js\";\n\nfunction hasAccessorOnPrototype(target: object, name: string): boolean {\n let proto = Object.getPrototypeOf(target);\n while (proto !== null) {\n const descriptor = Object.getOwnPropertyDescriptor(proto, name);\n if (descriptor !== undefined) {\n return typeof descriptor.get === \"function\" || typeof descriptor.set === \"function\";\n }\n proto = Object.getPrototypeOf(proto);\n }\n return false;\n}\n\n/**\n * `connectedCallback` の先頭で呼ぶ。宣言済み input のうち upgrade 前の代入で\n * accessor をシャドウしている own プロパティを、delete → 再代入で setter に通し直す。\n *\n * - 冪等: 再代入は accessor を通るので own プロパティは残らず、2 回目以降は no-op。\n * - 宣言に `inputs` が無い要素、`wcBindable` を持たない要素では何もしない。\n * - 値の意味は変えない。今まで捨てられていた代入が届くようになる一方向の変化。\n */\nexport function upgradeProperties(element: object): void {\n const declaration = (element as { constructor?: { wcBindable?: IWcBindable } }).constructor?.wcBindable;\n const inputs = declaration?.inputs;\n if (inputs === undefined) return;\n for (const input of inputs) {\n const name = input.name;\n if (!Object.prototype.hasOwnProperty.call(element, name)) continue;\n if (!hasAccessorOnPrototype(element, name)) continue;\n const record = element as Record<string, unknown>;\n const value = record[name];\n delete record[name];\n record[name] = value;\n }\n}\n","import { config } from \"../config.js\";\nimport { IWcBindable } from \"../types.js\";\nimport { RafCore } from \"../core/RafCore.js\";\nimport { registerAutoTrigger } from \"../autoTrigger.js\";\nimport { upgradeProperties } from \"../protocol/upgradeProperties.js\";\n\nexport class Raf extends HTMLElement {\n static hasConnectedCallbackPromise = true;\n static wcBindable: IWcBindable = {\n ...RafCore.wcBindable,\n properties: [\n ...RafCore.wcBindable.properties,\n { name: \"trigger\", event: \"wcs-raf:trigger-changed\", semantics: \"state\" },\n ],\n // Shell-level settable surface. `attribute` is a purely descriptive hint\n // (per SPEC-extensions.md the binding core does not act on it) naming the\n // mirrored HTML attribute, matching <wcs-timer>. `trigger` is a momentary\n // command-property with no backing attribute, so it carries no hint.\n // `start` / `stop` / `reset` / `pause` / `resume` commands are inherited\n // from the Core above. Deliberately absent vs <wcs-timer>: `interval`\n // (rAF has no period) and `immediate` (the first frame already IS the\n // next rendering opportunity — no earlier meaningful moment exists).\n inputs: [\n { name: \"once\", attribute: \"once\" },\n { name: \"repeat\", attribute: \"repeat\" },\n { name: \"manual\", attribute: \"manual\" },\n { name: \"trigger\" },\n ],\n };\n\n private _core: RafCore;\n private _trigger: boolean = false;\n private _connectedCallbackPromise: Promise<void> = Promise.resolve();\n private _internals: ElementInternals | null = null;\n\n constructor() {\n super();\n this._core = new RafCore(this);\n this._internals = this._initInternals();\n this._wireStates({\n \"wcs-raf:running-changed\": (d) => ({ running: d === true }),\n \"wcs-raf:suspended-changed\": (d) => ({ suspended: d === true }),\n });\n }\n\n // CSS state reflection (:state()) — debug-only snapshot getter. NOT part of\n // wc-bindable (not a bind target); see README \"CSS styling with :state()\".\n // MUST NOT return the live CustomStateSet (that would let callers write\n // states from outside, defeating the point of :state() being read-only).\n get debugStates(): string[] {\n return this._internals ? [...this._internals.states] : [];\n }\n\n private _initInternals(): ElementInternals | null {\n // never-throw (async-io-node-guidelines.md §3.6): attachInternals is absent\n // in happy-dom / older environments, and pre-125 Chromium rejects\n // non-dashed state names from states.add() (probed and discarded here).\n // Either case silently disables reflection — the component still works,\n // it just doesn't expose :state() selectors.\n try {\n if (typeof this.attachInternals !== \"function\") return null;\n const internals = this.attachInternals();\n internals.states.add(\"wcs-probe\");\n internals.states.delete(\"wcs-probe\");\n return internals;\n } catch {\n return null;\n }\n }\n\n private _wireStates(map: Record<string, (detail: any) => Record<string, boolean>>): void {\n if (this._internals === null) return;\n const states = this._internals.states;\n for (const [event, toStates] of Object.entries(map)) {\n this.addEventListener(event, (e) => {\n const debug = this.hasAttribute(\"debug-states\");\n for (const [name, on] of Object.entries(toStates((e as CustomEvent).detail))) {\n try {\n if (on) { states.add(name); } else { states.delete(name); }\n } catch { /* never-throw */ }\n if (debug) this.toggleAttribute(`data-wcs-state-${name}`, on);\n }\n });\n }\n }\n\n // SSR (§4.1/§4.4): the Shell exposes the Core's readiness so a server-side\n // renderer can await the connect-time probe before snapshotting. There is no\n // async probe here (observe() resolves immediately), but the contract is\n // uniform across IO nodes.\n get connectedCallbackPromise(): Promise<void> {\n return this._connectedCallbackPromise;\n }\n\n // --- Attribute accessors ---\n\n get once(): boolean {\n return this.hasAttribute(\"once\");\n }\n\n set once(value: boolean) {\n if (value) {\n this.setAttribute(\"once\", \"\");\n } else {\n this.removeAttribute(\"once\");\n }\n }\n\n get repeat(): number {\n const attr = this.getAttribute(\"repeat\");\n if (attr === null || attr.trim() === \"\") return 0;\n // Strict parse via Number() (\"3px\" -> NaN, not 3), matching <wcs-timer>.\n // Normalise any non-positive / non-numeric value to 0 (= unlimited).\n const parsed = Number(attr);\n return (Number.isFinite(parsed) && parsed > 0) ? parsed : 0;\n }\n\n set repeat(value: number) {\n this.setAttribute(\"repeat\", String(value));\n }\n\n get manual(): boolean {\n return this.hasAttribute(\"manual\");\n }\n\n set manual(value: boolean) {\n if (value) {\n this.setAttribute(\"manual\", \"\");\n } else {\n this.removeAttribute(\"manual\");\n }\n }\n\n // --- Core delegated getters ---\n\n get tick(): number {\n return this._core.tick;\n }\n\n get elapsed(): number {\n return this._core.elapsed;\n }\n\n get dt(): number {\n return this._core.dt;\n }\n\n get running(): boolean {\n return this._core.running;\n }\n\n get suspended(): boolean {\n return this._core.suspended;\n }\n\n // --- Command property ---\n\n get trigger(): boolean {\n return this._trigger;\n }\n\n set trigger(value: boolean) {\n // Momentary command-property: a false→true write starts the loop. Mirrors\n // <wcs-timer>. Prefer the command-token protocol (`command.start:\n // $command.begin`) for state-driven starts; this exists mainly for the DOM\n // click trigger and simple boolean bindings.\n const v = !!value;\n if (v) {\n this._trigger = true;\n this.start();\n this._trigger = false;\n // The `trigger-changed` event reports the momentary flag returning to\n // false, i.e. that the trigger property *changed* — it is deliberately\n // not gated on whether start() actually began a new run (same contract\n // as <wcs-timer>).\n this.dispatchEvent(new CustomEvent(\"wcs-raf:trigger-changed\", {\n detail: false,\n bubbles: true,\n }));\n }\n }\n\n // --- Commands ---\n\n start(): void {\n // `once` is sugar for \"fire exactly one frame\": map it to repeat=1, but\n // let an explicit repeat attribute win when both are present.\n const repeat = this.repeat > 0 ? this.repeat : (this.once ? 1 : 0);\n this._core.start({ repeat });\n }\n\n stop(): void {\n this._core.stop();\n }\n\n reset(): void {\n this._core.reset();\n }\n\n pause(): void {\n this._core.pause();\n }\n\n resume(): void {\n this._core.resume();\n }\n\n // --- Lifecycle ---\n\n connectedCallback(): void {\n // upgrade 前に代入された input を取り込み直す(doc 13 §1.2 / Phase A1)\n upgradeProperties(this);\n this.style.display = \"none\";\n if (config.autoTrigger) {\n registerAutoTrigger();\n }\n // Establish monitoring (§3.5): observe() subscribes visibilitychange (the\n // `suspended` output) and resolves once ready; expose it as\n // connectedCallbackPromise for SSR. Note for SSR pages: an auto-started\n // frame loop keeps scheduling — prefer `manual` in server-rendered markup\n // (see README).\n this._connectedCallbackPromise = this._core.observe();\n if (!this.manual) {\n this.start();\n }\n }\n\n disconnectedCallback(): void {\n // dispose() stops the loop, releases the visibility subscription and bumps\n // the generation so a frame already queued cannot fire onto a disconnected\n // element (§3.5 / §4.4).\n this._core.dispose();\n }\n}\n","import { Raf } from \"./components/Raf.js\";\nimport { config } from \"./config.js\";\n\nexport function registerComponents(): void {\n if (!customElements.get(config.tagNames.raf)) {\n customElements.define(config.tagNames.raf, Raf);\n }\n}\n"],"names":["config","triggerAttribute","tagNames","raf","RafCore","EventTarget","static","protocol","version","properties","name","event","semantics","getter","e","detail","count","elapsed","dt","commands","_target","_injectedScheduler","_handle","_globalScheduler","_gen","_ready","Promise","resolve","_tick","_dt","_elapsed","_running","_suspended","_paused","_lastTs","_repeat","_runStartTick","_visibilityDoc","constructor","target","scheduler","super","this","tick","running","suspended","ready","observe","document","addEventListener","_onVisibilityChange","_updateSuspended","dispose","stop","removeEventListener","_dispatchTick","timestamp","dispatchEvent","CustomEvent","bubbles","_setRunning","_setSuspended","hidden","visibilityState","start","options","_resolveScheduler","repeat","_requestFrame","_clearHandle","reset","pause","resume","_frame","g","globalThis","requestAnimationFrame","cancelAnimationFrame","request","cb","cancel","handle","gen","registered","handleClick","Element","triggerElement","closest","rafId","getAttribute","RafCtor","customElements","get","rafElement","getElementById","preventDefault","hasAccessorOnPrototype","proto","Object","getPrototypeOf","descriptor","getOwnPropertyDescriptor","undefined","set","Raf","HTMLElement","wcBindable","inputs","attribute","_core","_trigger","_connectedCallbackPromise","_internals","_initInternals","_wireStates","d","debugStates","states","attachInternals","internals","add","delete","map","toStates","entries","debug","hasAttribute","on","toggleAttribute","connectedCallbackPromise","once","value","setAttribute","removeAttribute","attr","trim","parsed","Number","isFinite","String","manual","trigger","connectedCallback","element","declaration","input","prototype","hasOwnProperty","call","record","upgradeProperties","style","display","disconnectedCallback","define"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"auto.min.js","sources":["../src/config.ts","../src/core/RafCore.ts","../src/autoTrigger.ts","../src/protocol/upgradeProperties.ts","../src/components/Raf.ts","../src/bootstrapRaf.ts","../src/registerComponents.ts"],"sourcesContent":["import { IConfig, IWritableConfig } from \"./types.js\";\n\ninterface IInternalConfig extends IConfig {\n autoTrigger: boolean;\n triggerAttribute: string;\n tagNames: {\n raf: string;\n };\n}\n\nconst _config: IInternalConfig = {\n autoTrigger: true,\n triggerAttribute: \"data-raftarget\",\n tagNames: {\n raf: \"wcs-raf\",\n },\n};\n\nfunction deepFreeze<T>(obj: T): T {\n if (obj === null || typeof obj !== \"object\") return obj;\n Object.freeze(obj);\n for (const key of Object.keys(obj)) {\n deepFreeze((obj as Record<string, unknown>)[key]);\n }\n return obj;\n}\n\nfunction deepClone<T>(obj: T): T {\n if (obj === null || typeof obj !== \"object\") return obj;\n const clone: Record<string, unknown> = {};\n for (const key of Object.keys(obj)) {\n clone[key] = deepClone((obj as Record<string, unknown>)[key]);\n }\n return clone as T;\n}\n\nlet frozenConfig: IConfig | null = null;\n\n// Internal-only live handle to the mutable config. NOT part of the public API\n// (deliberately absent from exports.ts) — it is exported solely so sibling\n// modules in this package can read current settings cheaply. External consumers\n// must use getConfig() (returns a deep-frozen snapshot) / setConfig(). Mutating\n// this object directly bypasses the frozenConfig cache and is unsupported.\nexport const config: IConfig = _config as IConfig;\n\nexport function getConfig(): IConfig {\n if (!frozenConfig) {\n frozenConfig = deepFreeze(deepClone(_config));\n }\n return frozenConfig;\n}\n\nexport function setConfig(partialConfig: IWritableConfig): void {\n if (typeof partialConfig.autoTrigger === \"boolean\") {\n _config.autoTrigger = partialConfig.autoTrigger;\n }\n if (typeof partialConfig.triggerAttribute === \"string\") {\n _config.triggerAttribute = partialConfig.triggerAttribute;\n }\n if (partialConfig.tagNames) {\n Object.assign(_config.tagNames, partialConfig.tagNames);\n }\n frozenConfig = null;\n}\n","import { IWcBindable } from \"../types.js\";\n\nexport interface RafStartOptions {\n repeat?: number;\n}\n\n/**\n * Injectable frame scheduler. The default resolves\n * `globalThis.requestAnimationFrame` / `cancelAnimationFrame` AT CALL TIME\n * (async-io-node-guidelines §3.7); tests inject a fake that pumps frames with\n * explicit timestamps (the `dt` contract is timestamp-derived, so tests must\n * control the clock, not just the callback order).\n *\n * Contract: `request()` MUST return a non-null handle. The core uses `null`\n * as its internal \"not armed\" sentinel, so a scheduler returning literal\n * `null` would silently corrupt the handle bookkeeping (re-entrancy guards\n * and cancel tracking). Native rAF returns a long, so this only concerns\n * custom scheduler injections — return a number, object, or any other\n * non-nullish token.\n */\nexport interface RafScheduler {\n request(callback: (timestamp: number) => void): unknown;\n cancel(handle: unknown): void;\n}\n\n/**\n * Injectable matchMedia pair for the `prefers-reduced-motion` gate. The\n * default resolves `globalThis.matchMedia` at call time; tests inject a fake\n * whose `matches` and `change` dispatch they control directly (happy-dom's\n * MQL change delivery is not reliable enough to drive the gate transitions\n * a 100/97 coverage target needs).\n */\nexport interface RafMediaQuery {\n readonly matches: boolean;\n addEventListener(type: \"change\", listener: () => void): void;\n removeEventListener(type: \"change\", listener: () => void): void;\n}\n\nexport type RafMatchMedia = (query: string) => RafMediaQuery;\n\n/**\n * Headless requestAnimationFrame primitive — `TimerCore`'s sibling with the\n * time source swapped from `setInterval` (a period) to rAF (the browser's\n * rendering opportunity). Exposed through the wc-bindable protocol: it streams\n * `tick` (frame counter), `elapsed` (accumulated ACTIVE milliseconds), `dt`\n * (delta to the previous frame) and the `running` / `suspended` pair, and is\n * driven by the `start` / `stop` / `reset` / `pause` / `resume` commands.\n *\n * `tick` / `elapsed` / `dt` are all surfaced via the single `wcs-raf:tick`\n * event (read through getters, mirroring how FetchCore exposes value/status\n * from one `wcs-fetch:response` event).\n *\n * Contracts specific to this node (docs/raf-tag-design.md):\n *\n * - **dt describes continuous running only.** The first frame after `start()`,\n * `resume()`, or a visibility interruption reports `dt = 0` — a value that\n * spans an interruption never reaches observers. Like `suspended`, the\n * visibility boundary is only detected once observe() has subscribed to\n * `visibilitychange`; a headless setup that skips observe() will see the\n * raw spanning delta on the first frame after a hidden gap. There is\n * deliberately NO upper clamp: how to treat a slow frame is the consumer's\n * domain decision.\n * - **elapsed is Σdt (active time).** Because interruption-spanning deltas are\n * normalized to 0, summing dt yields exactly the time frames were actually\n * being delivered — no separate segment bookkeeping is needed, and hidden /\n * paused periods contribute nothing. Granularity is one frame: between\n * frames the getter returns the value as of the last tick.\n * - **running / suspended are a desired/actual pair** (the wakelock split): in\n * a hidden tab the browser delivers no frames at all, so `running` (the\n * started intent) stays true while `suspended` reports that delivery is\n * actually stopped. `suspended` is only meaningful after `observe()` has\n * subscribed to `visibilitychange`; without a document it stays false.\n * - **`suspended` has two causes**: `running && (hidden || reducedGate)`.\n * The second cause is the opt-in `prefers-reduced-motion` gate\n * (`reducedMotion === \"pause\"` while the media query matches —\n * docs/a11y-design.md §6). It is deliberately NOT a `pause()` reuse:\n * `_paused` is user intent (cleared by `start()`/`stop()`), and mixing an\n * environment condition into it would let `resume()` override the OS\n * setting. Unlike visibility — where the browser itself stops delivering\n * frames — the reduced gate is enforced by this core: gate ON cancels the\n * armed frame, gate OFF re-arms with a dt=0 boundary (G3, the same shape\n * as a visibility interruption).\n * - **No `error` surface.** rAF has no persistent failure mode; on a platform\n * without it, `start()` is a silent no-op (never-throw, resize precedent).\n */\nexport class RafCore extends EventTarget {\n static wcBindable: IWcBindable = {\n protocol: \"wc-bindable\",\n version: 1,\n properties: [\n { name: \"tick\", event: \"wcs-raf:tick\", semantics: \"state\", getter: (e: Event) => (e as CustomEvent).detail.count },\n { name: \"elapsed\", event: \"wcs-raf:tick\", semantics: \"state\", getter: (e: Event) => (e as CustomEvent).detail.elapsed },\n { name: \"dt\", event: \"wcs-raf:tick\", semantics: \"state\", getter: (e: Event) => (e as CustomEvent).detail.dt },\n { name: \"running\", event: \"wcs-raf:running-changed\", semantics: \"state\" },\n { name: \"suspended\", event: \"wcs-raf:suspended-changed\", semantics: \"state\" },\n ],\n commands: [\n { name: \"start\" },\n { name: \"stop\" },\n { name: \"reset\" },\n { name: \"pause\" },\n { name: \"resume\" },\n ],\n };\n\n private _target: EventTarget;\n private _injectedScheduler: RafScheduler | null;\n private _handle: unknown = null;\n\n // Lazily-created wrapper around the global rAF pair, cached so the hot\n // frame-reschedule path (_frame, once per delivered frame) does not\n // allocate a new object + closures every call. `request`/`cancel` still\n // dereference `globalThis.requestAnimationFrame` / `cancelAnimationFrame`\n // live on every invocation (they are not snapshotted here), so call-time\n // resolution (§3.7) is unchanged — only the wrapper object itself is\n // reused once the global functions are first found present.\n private _globalScheduler: RafScheduler | null = null;\n\n // Generation guard (§3.4): a monotonic arming counter. Bumped when a run is\n // armed (start()/resume()), when an armed handle is cancelled\n // (_clearHandle()) and on dispose(). _requestFrame() captures the value in\n // each request's closure and drops the frame if it no longer matches the\n // live field when it fires. cancel() is best-effort against a non-compliant\n // scheduler; the captured generation is the guarantee — a stale callback can\n // neither mutate state, dispatch on a torn-down element, nor corrupt a\n // newer run's `_handle` bookkeeping. A live-field comparison (the previous\n // `_runGen` scheme) could not survive a dispose() → start() round trip: the\n // new start() re-synced the pair and let the stale callback through,\n // permanently doubling the frame loop.\n private _gen = 0;\n // SSR (§3.8): there is no asynchronous probe, so readiness is immediate.\n private _ready: Promise<void> = Promise.resolve();\n\n private _tick: number = 0;\n private _dt: number = 0;\n private _elapsed: number = 0;\n private _running: boolean = false;\n private _suspended: boolean = false;\n private _paused: boolean = false;\n\n // Timestamp of the previous frame within the current continuous run.\n // `null` means \"the next frame starts a run segment\": its dt is reported as\n // 0 (the G3 normalization). Cleared at start()/resume() and on every\n // visibilitychange (an interruption boundary).\n private _lastTs: number | null = null;\n\n // `_tick` value captured at the start of the current run. `repeat` counts\n // frames *per run*, so the stop condition compares against this baseline\n // rather than the cumulative `_tick` (which only resets on reset()).\n private _repeat: number = 0;\n private _runStartTick: number = 0;\n\n // The document whose visibility drives `suspended`, subscribed in observe()\n // and released in dispose(). Null before observe() or in non-DOM\n // environments — `suspended` then simply stays false.\n private _visibilityDoc: Document | null = null;\n\n // The reduced-motion policy (\"run\" = ignore the preference, the default)\n // and the media query subscribed in observe() / released in dispose().\n // The live `change` subscription is MANDATORY, not an optimization: with a\n // start-time check only, a loop started while reduce is active would sit\n // running=true with no armed frame and no way to ever notice the\n // preference clearing — a permanent wedge (docs/a11y-design.md §6-2).\n private _reducedMotion: \"run\" | \"pause\" = \"run\";\n private _mql: RafMediaQuery | null = null;\n private _injectedMatchMedia: RafMatchMedia | null;\n\n constructor(target?: EventTarget, scheduler?: RafScheduler, matchMedia?: RafMatchMedia) {\n super();\n this._target = target ?? this;\n this._injectedScheduler = scheduler ?? null;\n this._injectedMatchMedia = matchMedia ?? null;\n }\n\n get tick(): number {\n return this._tick;\n }\n\n get elapsed(): number {\n return this._elapsed;\n }\n\n get dt(): number {\n return this._dt;\n }\n\n get running(): boolean {\n return this._running;\n }\n\n get suspended(): boolean {\n return this._suspended;\n }\n\n get reducedMotion(): \"run\" | \"pause\" {\n return this._reducedMotion;\n }\n\n set reducedMotion(value: \"run\" | \"pause\") {\n // ポリシー変更はゲート入力の変化(MQL change と同じ扱い)。値の正規化\n // (未知 → \"run\")は Shell の担当で、Core は正規化済みの 2 値だけを受ける。\n if (this._reducedMotion === value) return;\n this._reducedMotion = value;\n this._applyReducedGate();\n }\n\n // SSR readiness (§3.8): resolves after the first probe. There is nothing to\n // probe, so this is an already-resolved promise.\n get ready(): Promise<void> {\n return this._ready;\n }\n\n // Lifecycle (§3.5). observe() establishes the one ambient subscription this\n // node has — `visibilitychange`, which drives the `suspended` output and the\n // dt=0 normalization across a hidden period. Idempotent; a no-op without a\n // document (SSR pre-pass, worker). dispose() tears everything down and bumps\n // the generation so a frame already queued cannot fire onto a torn-down\n // element.\n observe(): Promise<void> {\n if (this._visibilityDoc === null && typeof document !== \"undefined\") {\n this._visibilityDoc = document;\n document.addEventListener(\"visibilitychange\", this._onVisibilityChange);\n // Sync `suspended` to the visibility state at subscription time: with a\n // start()-before-observe() ordering (headless Core usage) the document\n // may already be hidden, and waiting for the next visibilitychange\n // would report suspended=false until then. Same-value guarded, so the\n // common visible-at-observe case dispatches nothing.\n this._updateSuspended();\n }\n if (this._mql === null) {\n const matchMedia = this._resolveMatchMedia();\n if (matchMedia !== null) {\n // never-throw(view-transition の ViewTransitionCore と同じ先例):\n // 変な UA の matchMedia 例外で observe() 全体を殺さない。\n try {\n const mql = matchMedia(\"(prefers-reduced-motion: reduce)\");\n mql.addEventListener(\"change\", this._onReducedMotionChange);\n this._mql = mql;\n // 購読時点の preference を反映する(visibility の同期と同じ理由:\n // reduce 中に observe された場合、次の change を待つと偽の\n // suspended=false を報告し、アーム済みフレームも生き残る)。\n this._applyReducedGate();\n } catch {\n this._mql = null;\n }\n }\n }\n return this._ready;\n }\n\n dispose(): void {\n this._gen++;\n this.stop();\n if (this._visibilityDoc !== null) {\n this._visibilityDoc.removeEventListener(\"visibilitychange\", this._onVisibilityChange);\n this._visibilityDoc = null;\n }\n if (this._mql !== null) {\n this._mql.removeEventListener(\"change\", this._onReducedMotionChange);\n this._mql = null;\n }\n }\n\n // --- State setters with event dispatch ---\n\n private _dispatchTick(timestamp: number): void {\n this._target.dispatchEvent(new CustomEvent(\"wcs-raf:tick\", {\n detail: { count: this._tick, elapsed: this._elapsed, dt: this._dt, timestamp },\n bubbles: true,\n }));\n }\n\n private _setRunning(running: boolean): void {\n if (this._running === running) return;\n this._running = running;\n this._target.dispatchEvent(new CustomEvent(\"wcs-raf:running-changed\", {\n detail: running,\n bubbles: true,\n }));\n // `suspended` is derived from (running && hidden), so every running\n // transition re-evaluates it: stop/pause drop a suspension, and a start()\n // inside an already-hidden tab reports it immediately (honestly: no frame\n // will arrive until the tab is visible again).\n this._updateSuspended();\n }\n\n private _setSuspended(suspended: boolean): void {\n if (this._suspended === suspended) return;\n this._suspended = suspended;\n this._target.dispatchEvent(new CustomEvent(\"wcs-raf:suspended-changed\", {\n detail: suspended,\n bubbles: true,\n }));\n }\n\n private _updateSuspended(): void {\n // suspended の 2 原因: visibility と reduced-motion ゲート(クラスコメント参照)\n const hidden = this._visibilityDoc !== null && this._visibilityDoc.visibilityState === \"hidden\";\n this._setSuspended(this._running && (hidden || this._reducedGate()));\n }\n\n // The reduced gate is active only when the author opted in (\"pause\") AND\n // the subscribed media query currently matches. Before observe() — or\n // without matchMedia — there is no subscription and the gate stays open.\n private _reducedGate(): boolean {\n return this._reducedMotion === \"pause\" && this._mql !== null && this._mql.matches;\n }\n\n private _onReducedMotionChange = (): void => {\n this._applyReducedGate();\n };\n\n // Reflect the current gate value into the run state. Unlike visibility —\n // where the browser itself stops delivering frames and the armed handle can\n // stay put — the reduced gate is enforced here: ON cancels the armed frame\n // (through _clearHandle, so the generation guard also invalidates an\n // in-flight callback), OFF re-arms exactly one loop with a dt=0 interruption\n // boundary (G3). The `_handle === null` check keeps a redundant change event\n // from stacking a second loop; the re-arm is a no-op while paused-by-user\n // (`_running` false) or already armed.\n private _applyReducedGate(): void {\n if (this._running) {\n if (this._reducedGate()) {\n this._clearHandle();\n } else if (this._handle === null) {\n this._lastTs = null;\n const scheduler = this._resolveScheduler();\n if (scheduler !== null) {\n this._requestFrame(scheduler);\n }\n }\n }\n this._updateSuspended();\n }\n\n // --- Public API ---\n\n start(options: RafStartOptions = {}): void {\n // Idempotent while running: a redundant start() must not stack a second\n // frame loop (which would double the tick rate). Reconfiguring an active\n // run is done via stop() + start().\n if (this._running) return;\n\n // Resolve the platform API at call time (§3.7). Absent rAF (SSR pre-pass,\n // worker) makes start() a silent no-op — never-throw, and this node has no\n // error surface by design.\n const scheduler = this._resolveScheduler();\n if (scheduler === null) return;\n\n // start() begins a fresh run, so clear any lingering pause from a prior\n // pause()-without-resume(). Without this, the loop would run while _paused\n // stayed true, leaving pause() a no-op and letting resume() overwrite the\n // live handle (leak + double fire).\n this._paused = false;\n\n // `repeat` is per-run intent, NOT persistent configuration: every start()\n // re-establishes it from the options, defaulting to \"unlimited\" when\n // omitted. This keeps a bare start() after a bounded run from silently\n // inheriting the old bounds.\n this._repeat = (typeof options.repeat === \"number\" && options.repeat > 0) ? options.repeat : 0;\n\n // New arming generation (§3.4): invalidates any callback still in flight\n // from a previous run (e.g. one whose cancel() a non-compliant scheduler\n // ignored). Bumped BEFORE the running-changed dispatch below, so that a\n // re-entrant restart from a listener arms with the newest generation —\n // the re-entrancy guard then keeps this outer call from arming (and\n // bumping) on top of it.\n this._gen++;\n\n this._setRunning(true);\n // Baseline this run's per-run repeat counting (set after _setRunning so a\n // re-start of a completed bounded run fires the full N frames again).\n this._runStartTick = this._tick;\n // G3: the first frame of a run reports dt = 0.\n this._lastTs = null;\n\n // Re-entrancy guard: _setRunning(true) just dispatched running-changed\n // synchronously, and a listener may have changed the world from inside it.\n // - `!_running`: the listener called stop()/pause()/dispose(). Without\n // this check a \"ghost\" frame would still be scheduled for an\n // already-stopped run — it would either tick once while running stays\n // false, or leave an uncancellable handle behind.\n // - `_handle !== null`: the listener restarted the loop itself\n // (stop()→start()); the inner start() already armed the new run, and\n // requesting again here would overwrite `_handle` (losing the inner\n // handle, never cancelled) and stack a permanent second frame loop.\n // On the normal path `_handle` is always null here — every transition\n // to `_running === false` clears it — so non-null can only mean a\n // re-entrant listener already scheduled the run for us.\n if (!this._running || this._handle !== null) return;\n // reduce ゲート中の start(): running=true / suspended=true のまま非アーム。\n // ゲート解除は MQL change → _applyReducedGate() が再アームする(§6-2)。\n if (this._reducedGate()) return;\n this._requestFrame(scheduler);\n }\n\n stop(): void {\n this._clearHandle();\n this._paused = false;\n this._setRunning(false);\n }\n\n reset(): void {\n this._clearHandle();\n this._paused = false;\n this._tick = 0;\n this._elapsed = 0;\n this._dt = 0;\n this._lastTs = null;\n this._setRunning(false);\n // Notify observers that the counter/elapsed/dt have returned to zero. The\n // notification is not a frame, so `timestamp` is 0 (see WcsRafTickDetail).\n this._dispatchTick(0);\n }\n\n pause(): void {\n // Pause only a live loop; a no-op otherwise so it composes safely with the\n // declarative lifecycle. Unlike stop(), it records `_paused` so resume()\n // can tell an intentional pause from a full stop. No elapsed bookkeeping\n // is needed: elapsed is Σdt, and the resume boundary's dt is 0.\n if (!this._running || this._paused) return;\n this._clearHandle();\n this._paused = true;\n this._setRunning(false);\n }\n\n resume(): void {\n if (!this._paused) return;\n const scheduler = this._resolveScheduler();\n if (scheduler === null) return;\n this._paused = false;\n // New arming generation (§3.4), bumped before the running-changed\n // dispatch for the same re-entrancy reason as start().\n this._gen++;\n this._setRunning(true);\n // G3: the first frame after a pause reports dt = 0 (elapsed therefore does\n // not count the paused period — the \"active time\" contract).\n this._lastTs = null;\n\n // Re-entrancy guard, for the same reasons as start() (see the comment\n // there): a running-changed listener may have synchronously stopped this\n // node — or restarted it, leaving `_handle` already armed — from inside\n // _setRunning(true) above.\n if (!this._running || this._handle !== null) return;\n // reduce ゲート中は非アーム(start() と同じ)\n if (this._reducedGate()) return;\n this._requestFrame(scheduler);\n }\n\n // --- Internal ---\n\n private _frame = (timestamp: number): void => {\n // Reached only through _requestFrame's generation-checked closure (§3.4):\n // a stale callback — disposed, cancelled by a non-compliant scheduler, or\n // superseded by a newer run — never gets here.\n this._handle = null;\n\n // dt: delta to the previous frame within this continuous run; 0 when this\n // frame opens a segment (start/resume/visibility boundary — G3).\n const dt = this._lastTs === null ? 0 : timestamp - this._lastTs;\n this._lastTs = timestamp;\n\n this._tick++;\n this._dt = dt;\n this._elapsed += dt;\n this._dispatchTick(timestamp);\n\n // Auto-stop once this run has fired the requested number of frames\n // (repeat=0 runs forever). Counted per-run via `_runStartTick`, so a\n // re-start after a completed bounded run fires N frames again. `once` is\n // expressed by the Shell as repeat=1.\n //\n // The cleanup mirrors stop() exactly, because a tick listener may have\n // synchronously paused — or paused and resumed — DURING the final frame's\n // dispatch above. The run's budget is exhausted either way, so clear the\n // pause (a later resume() must be a no-op, not an N+1th frame) and cancel\n // any handle a re-entrant resume() armed (it would otherwise survive as a\n // ghost frame and tick past the budget). On the normal path both are\n // already clear (no-ops). A stop()→start() restart is NOT affected: the\n // new run re-baselines `_runStartTick`, so this branch is not taken.\n if (this._repeat > 0 && (this._tick - this._runStartTick) >= this._repeat) {\n this._clearHandle();\n this._paused = false;\n this._setRunning(false);\n return;\n }\n\n // Re-request the next frame — unless a tick listener stopped the loop\n // synchronously during the dispatch above, or already scheduled a new run\n // itself (a synchronous stop()→start() / pause()→resume() restart leaves\n // _handle non-null; re-requesting on top of it would stack a permanent\n // second frame loop. The generation guard cannot catch this: a tail\n // request here would capture the restart's own — current — generation\n // and produce a second equally-valid loop).\n //\n // The reduced-gate check matters here too: a tick listener may have\n // flipped the policy during the dispatch above. _applyReducedGate() ran\n // then, but inside a frame `_handle` is already null (cleared on entry),\n // so its _clearHandle() was a no-op and did NOT bump the generation —\n // without this check the tail would happily re-arm through the gate.\n if (this._running && this._handle === null && !this._reducedGate()) {\n const scheduler = this._resolveScheduler();\n if (scheduler !== null) {\n this._requestFrame(scheduler);\n }\n }\n };\n\n private _onVisibilityChange = (): void => {\n // Either direction is an interruption boundary: entering hidden means the\n // browser stops delivering frames, so the NEXT delivered frame must not\n // report a delta spanning the gap (G3). Clearing on the visible edge too\n // is belt-and-braces for a missed hidden event — the worst case is one\n // extra dt=0 frame.\n this._lastTs = null;\n this._updateSuspended();\n };\n\n private _resolveScheduler(): RafScheduler | null {\n if (this._injectedScheduler !== null) return this._injectedScheduler;\n const g = globalThis as unknown as {\n requestAnimationFrame?: (cb: (ts: number) => void) => unknown;\n cancelAnimationFrame?: (handle: unknown) => void;\n };\n // The availability check itself still runs on every call (§3.7: resolved\n // at call time, not cached across an absence/presence flip).\n if (typeof g.requestAnimationFrame !== \"function\" || typeof g.cancelAnimationFrame !== \"function\") {\n return null;\n }\n if (this._globalScheduler === null) {\n // `g` is just a typed alias for `globalThis` (not a snapshot), so these\n // closures keep dereferencing the live global functions even though the\n // wrapper object itself is created only once.\n this._globalScheduler = {\n request: (cb) => g.requestAnimationFrame!(cb),\n cancel: (handle) => g.cancelAnimationFrame!(handle),\n };\n }\n return this._globalScheduler;\n }\n\n private _resolveMatchMedia(): RafMatchMedia | null {\n if (this._injectedMatchMedia !== null) return this._injectedMatchMedia;\n const g = globalThis as unknown as {\n matchMedia?: (query: string) => RafMediaQuery;\n };\n // §3.7: availability is checked at call time (observe() may be called in\n // SSR pre-pass or a worker, where matchMedia is absent — the gate then\n // simply never engages).\n if (typeof g.matchMedia !== \"function\") {\n return null;\n }\n return (query) => g.matchMedia!(query);\n }\n\n // Arm the next frame (§3.4). The callback closes over the generation\n // current at request time and re-checks it against the live `_gen` when the\n // frame arrives; a callback that outlived its run bails here. See the\n // `_gen` field comment for why this must be a per-request capture and not a\n // live-field comparison.\n private _requestFrame(scheduler: RafScheduler): void {\n const gen = this._gen;\n this._handle = scheduler.request((timestamp: number) => {\n if (gen !== this._gen) return;\n this._frame(timestamp);\n });\n }\n\n private _clearHandle(): void {\n if (this._handle !== null) {\n this._resolveScheduler()?.cancel(this._handle);\n this._handle = null;\n // Invalidate the cancelled callback's captured generation as well:\n // cancel() is best-effort against a non-compliant scheduler, the\n // generation is the guarantee (§3.4).\n this._gen++;\n }\n }\n}\n","import { config } from \"./config.js\";\nimport type { Raf } from \"./components/Raf.js\";\n\nlet registered = false;\n\nfunction handleClick(event: Event): void {\n const target = event.target;\n if (!(target instanceof Element)) return;\n\n const triggerElement = target.closest<Element>(`[${config.triggerAttribute}]`);\n if (!triggerElement) return;\n\n const rafId = triggerElement.getAttribute(config.triggerAttribute);\n if (!rafId) return;\n\n // Resolve the registered constructor at call time instead of importing Raf\n // as a value. The value import created a components/Raf.ts ⇄ autoTrigger.ts\n // cycle (Raf.connectedCallback() calls registerAutoTrigger()). instanceof\n // against the customElements registry keeps the exact same identity guarantee\n // — only the registered <wcs-raf> class matches — without the import cycle.\n const RafCtor = customElements.get(config.tagNames.raf);\n const rafElement = document.getElementById(rafId);\n if (!RafCtor || !(rafElement instanceof RafCtor)) return;\n\n // Suppress the element's default action so a loop can start without\n // navigating. Intentional: do not attach data-raftarget to an element whose\n // default action you also want (real <a href> link, form-submit button) — it\n // will be cancelled. See README \"Optional DOM Triggering\".\n event.preventDefault();\n (rafElement as Raf).start();\n}\n\nexport function registerAutoTrigger(): void {\n if (registered) return;\n registered = true;\n document.addEventListener(\"click\", handleClick);\n}\n\nexport function unregisterAutoTrigger(): void {\n if (!registered) return;\n registered = false;\n document.removeEventListener(\"click\", handleClick);\n}\n","// ===========================================================================\n// AUTO-GENERATED FILE - DO NOT EDIT.\n// Generated from /protocol/upgrade-properties.ts by scripts/sync-protocol-types.mjs.\n// Run `node scripts/sync-protocol-types.mjs` after editing the source.\n// ===========================================================================\n\n// custom element の property upgrade — `static wcBindable.inputs` に宣言した入力のうち、\n// 要素が upgrade される前に代入された own データプロパティを取り込み直す。\n//\n// なぜ必要か:\n// 未定義タグの要素は素の HTMLElement なので、`el.url = \"...\"` は own データプロパティを作る。\n// upgrade 後にクラスの accessor が prototype へ入っても own プロパティが優先されるため、\n// setter は二度と呼ばれず、値は要素へ届かないまま消える(エラーも警告も出ない)。\n// 常にプロパティ代入を行う framework(Angular の `[prop]`、Lit の `.prop=`、\n// Solid の `prop:`、Vue の `.prop` 修飾子)× 遅延定義(autoloader / CDN / code-split)で\n// 常態的に起きる。docs/architecture-hardening/13-framework-adapter-binding-constraints.md §1.2。\n//\n// 安全側の判定:\n// own プロパティがあっても、prototype チェーンに accessor が無ければ「シャドウ」ではなく\n// その own プロパティ自体が正規の格納先なので触らない(public class field を壊さない)。\n//\n// SINGLE SOURCE OF TRUTH: edit only this file (/protocol/upgrade-properties.ts), then run\n// `node scripts/sync-protocol-types.mjs` to regenerate the per-package copies\n// (packages/<pkg>/src/protocol/upgradeProperties.ts). Those copies are generated — do not edit them.\nimport { IWcBindable } from \"./wcBindable.js\";\n\nfunction hasAccessorOnPrototype(target: object, name: string): boolean {\n let proto = Object.getPrototypeOf(target);\n while (proto !== null) {\n const descriptor = Object.getOwnPropertyDescriptor(proto, name);\n if (descriptor !== undefined) {\n return typeof descriptor.get === \"function\" || typeof descriptor.set === \"function\";\n }\n proto = Object.getPrototypeOf(proto);\n }\n return false;\n}\n\n/**\n * `connectedCallback` の先頭で呼ぶ。宣言済み input のうち upgrade 前の代入で\n * accessor をシャドウしている own プロパティを、delete → 再代入で setter に通し直す。\n *\n * - 冪等: 再代入は accessor を通るので own プロパティは残らず、2 回目以降は no-op。\n * - 宣言に `inputs` が無い要素、`wcBindable` を持たない要素では何もしない。\n * - 値の意味は変えない。今まで捨てられていた代入が届くようになる一方向の変化。\n */\nexport function upgradeProperties(element: object): void {\n const declaration = (element as { constructor?: { wcBindable?: IWcBindable } }).constructor?.wcBindable;\n const inputs = declaration?.inputs;\n if (inputs === undefined) return;\n for (const input of inputs) {\n const name = input.name;\n if (!Object.prototype.hasOwnProperty.call(element, name)) continue;\n if (!hasAccessorOnPrototype(element, name)) continue;\n const record = element as Record<string, unknown>;\n const value = record[name];\n delete record[name];\n record[name] = value;\n }\n}\n","import { config } from \"../config.js\";\nimport { IWcBindable } from \"../types.js\";\nimport { RafCore } from \"../core/RafCore.js\";\nimport { registerAutoTrigger } from \"../autoTrigger.js\";\nimport { upgradeProperties } from \"../protocol/upgradeProperties.js\";\n\nexport class Raf extends HTMLElement {\n static hasConnectedCallbackPromise = true;\n static wcBindable: IWcBindable = {\n ...RafCore.wcBindable,\n properties: [\n ...RafCore.wcBindable.properties,\n { name: \"trigger\", event: \"wcs-raf:trigger-changed\", semantics: \"state\" },\n ],\n // Shell-level settable surface. `attribute` is a purely descriptive hint\n // (per SPEC-extensions.md the binding core does not act on it) naming the\n // mirrored HTML attribute, matching <wcs-timer>. `trigger` is a momentary\n // command-property with no backing attribute, so it carries no hint.\n // `start` / `stop` / `reset` / `pause` / `resume` commands are inherited\n // from the Core above. Deliberately absent vs <wcs-timer>: `interval`\n // (rAF has no period) and `immediate` (the first frame already IS the\n // next rendering opportunity — no earlier meaningful moment exists).\n inputs: [\n { name: \"once\", attribute: \"once\" },\n { name: \"repeat\", attribute: \"repeat\" },\n { name: \"manual\", attribute: \"manual\" },\n { name: \"reducedMotion\", attribute: \"reduced-motion\" },\n { name: \"trigger\" },\n ],\n };\n\n static get observedAttributes(): string[] {\n return [\"reduced-motion\"];\n }\n\n private _core: RafCore;\n private _trigger: boolean = false;\n private _connectedCallbackPromise: Promise<void> = Promise.resolve();\n private _internals: ElementInternals | null = null;\n\n constructor() {\n super();\n this._core = new RafCore(this);\n this._internals = this._initInternals();\n this._wireStates({\n \"wcs-raf:running-changed\": (d) => ({ running: d === true }),\n \"wcs-raf:suspended-changed\": (d) => ({ suspended: d === true }),\n });\n }\n\n // CSS state reflection (:state()) — debug-only snapshot getter. NOT part of\n // wc-bindable (not a bind target); see README \"CSS styling with :state()\".\n // MUST NOT return the live CustomStateSet (that would let callers write\n // states from outside, defeating the point of :state() being read-only).\n get debugStates(): string[] {\n return this._internals ? [...this._internals.states] : [];\n }\n\n private _initInternals(): ElementInternals | null {\n // never-throw (async-io-node-guidelines.md §3.6): attachInternals is absent\n // in happy-dom / older environments, and pre-125 Chromium rejects\n // non-dashed state names from states.add() (probed and discarded here).\n // Either case silently disables reflection — the component still works,\n // it just doesn't expose :state() selectors.\n try {\n if (typeof this.attachInternals !== \"function\") return null;\n const internals = this.attachInternals();\n internals.states.add(\"wcs-probe\");\n internals.states.delete(\"wcs-probe\");\n return internals;\n } catch {\n return null;\n }\n }\n\n private _wireStates(map: Record<string, (detail: any) => Record<string, boolean>>): void {\n if (this._internals === null) return;\n const states = this._internals.states;\n for (const [event, toStates] of Object.entries(map)) {\n this.addEventListener(event, (e) => {\n const debug = this.hasAttribute(\"debug-states\");\n for (const [name, on] of Object.entries(toStates((e as CustomEvent).detail))) {\n try {\n if (on) { states.add(name); } else { states.delete(name); }\n } catch { /* never-throw */ }\n if (debug) this.toggleAttribute(`data-wcs-state-${name}`, on);\n }\n });\n }\n }\n\n // SSR (§4.1/§4.4): the Shell exposes the Core's readiness so a server-side\n // renderer can await the connect-time probe before snapshotting. There is no\n // async probe here (observe() resolves immediately), but the contract is\n // uniform across IO nodes.\n get connectedCallbackPromise(): Promise<void> {\n return this._connectedCallbackPromise;\n }\n\n // --- Attribute accessors ---\n\n get once(): boolean {\n return this.hasAttribute(\"once\");\n }\n\n set once(value: boolean) {\n if (value) {\n this.setAttribute(\"once\", \"\");\n } else {\n this.removeAttribute(\"once\");\n }\n }\n\n get repeat(): number {\n const attr = this.getAttribute(\"repeat\");\n if (attr === null || attr.trim() === \"\") return 0;\n // Strict parse via Number() (\"3px\" -> NaN, not 3), matching <wcs-timer>.\n // Normalise any non-positive / non-numeric value to 0 (= unlimited).\n const parsed = Number(attr);\n return (Number.isFinite(parsed) && parsed > 0) ? parsed : 0;\n }\n\n set repeat(value: number) {\n this.setAttribute(\"repeat\", String(value));\n }\n\n get manual(): boolean {\n return this.hasAttribute(\"manual\");\n }\n\n set manual(value: boolean) {\n if (value) {\n this.setAttribute(\"manual\", \"\");\n } else {\n this.removeAttribute(\"manual\");\n }\n }\n\n get reducedMotion(): \"run\" | \"pause\" {\n return this._core.reducedMotion;\n }\n\n set reducedMotion(value: string) {\n // 属性へミラーし、attributeChangedCallback が正規化して Core へ届ける\n this.setAttribute(\"reduced-motion\", value);\n }\n\n attributeChangedCallback(name: string, _oldValue: string | null, newValue: string | null): void {\n if (name === \"reduced-motion\") {\n // 未知値・属性なしは既定 \"run\" へ正規化(view-transition の setter 慣行)。\n // once/repeat と違い start 時の遅延読みでは足りない — ポリシーは実行中の\n // ループにも効く(reduce 中の付け外しがゲートの付け外し)ため、変更時に\n // Core へ届ける。\n this._core.reducedMotion = newValue === \"pause\" ? \"pause\" : \"run\";\n }\n }\n\n // --- Core delegated getters ---\n\n get tick(): number {\n return this._core.tick;\n }\n\n get elapsed(): number {\n return this._core.elapsed;\n }\n\n get dt(): number {\n return this._core.dt;\n }\n\n get running(): boolean {\n return this._core.running;\n }\n\n get suspended(): boolean {\n return this._core.suspended;\n }\n\n // --- Command property ---\n\n get trigger(): boolean {\n return this._trigger;\n }\n\n set trigger(value: boolean) {\n // Momentary command-property: a false→true write starts the loop. Mirrors\n // <wcs-timer>. Prefer the command-token protocol (`command.start:\n // $command.begin`) for state-driven starts; this exists mainly for the DOM\n // click trigger and simple boolean bindings.\n const v = !!value;\n if (v) {\n this._trigger = true;\n this.start();\n this._trigger = false;\n // The `trigger-changed` event reports the momentary flag returning to\n // false, i.e. that the trigger property *changed* — it is deliberately\n // not gated on whether start() actually began a new run (same contract\n // as <wcs-timer>).\n this.dispatchEvent(new CustomEvent(\"wcs-raf:trigger-changed\", {\n detail: false,\n bubbles: true,\n }));\n }\n }\n\n // --- Commands ---\n\n start(): void {\n // `once` is sugar for \"fire exactly one frame\": map it to repeat=1, but\n // let an explicit repeat attribute win when both are present.\n const repeat = this.repeat > 0 ? this.repeat : (this.once ? 1 : 0);\n this._core.start({ repeat });\n }\n\n stop(): void {\n this._core.stop();\n }\n\n reset(): void {\n this._core.reset();\n }\n\n pause(): void {\n this._core.pause();\n }\n\n resume(): void {\n this._core.resume();\n }\n\n // --- Lifecycle ---\n\n connectedCallback(): void {\n // upgrade 前に代入された input を取り込み直す(doc 13 §1.2 / Phase A1)\n upgradeProperties(this);\n this.style.display = \"none\";\n if (config.autoTrigger) {\n registerAutoTrigger();\n }\n // Establish monitoring (§3.5): observe() subscribes visibilitychange (the\n // `suspended` output) and resolves once ready; expose it as\n // connectedCallbackPromise for SSR. Note for SSR pages: an auto-started\n // frame loop keeps scheduling — prefer `manual` in server-rendered markup\n // (see README).\n this._connectedCallbackPromise = this._core.observe();\n if (!this.manual) {\n this.start();\n }\n }\n\n disconnectedCallback(): void {\n // dispose() stops the loop, releases the visibility subscription and bumps\n // the generation so a frame already queued cannot fire onto a disconnected\n // element (§3.5 / §4.4).\n this._core.dispose();\n }\n}\n","import { setConfig } from \"./config.js\";\nimport { registerComponents } from \"./registerComponents.js\";\nimport { IWritableConfig } from \"./types.js\";\n\nexport function bootstrapRaf(userConfig?: IWritableConfig, registry?: CustomElementRegistry): void {\n if (userConfig) {\n setConfig(userConfig);\n }\n registerComponents(registry);\n}\n","import { Raf } from \"./components/Raf.js\";\nimport { config } from \"./config.js\";\n\n/**\n * Register this package's tags. Pass a scoped `CustomElementRegistry` to define\n * them for a single shadow tree -- scoped registries do not inherit the global\n * one, so a tree using one needs its own definitions.\n */\nexport function registerComponents(registry: CustomElementRegistry = customElements): void {\n if (!registry.get(config.tagNames.raf)) {\n registry.define(config.tagNames.raf, Raf);\n }\n}\n"],"names":["config","triggerAttribute","tagNames","raf","RafCore","EventTarget","static","protocol","version","properties","name","event","semantics","getter","e","detail","count","elapsed","dt","commands","_target","_injectedScheduler","_handle","_globalScheduler","_gen","_ready","Promise","resolve","_tick","_dt","_elapsed","_running","_suspended","_paused","_lastTs","_repeat","_runStartTick","_visibilityDoc","_reducedMotion","_mql","_injectedMatchMedia","constructor","target","scheduler","matchMedia","super","this","tick","running","suspended","reducedMotion","value","_applyReducedGate","ready","observe","document","addEventListener","_onVisibilityChange","_updateSuspended","_resolveMatchMedia","mql","_onReducedMotionChange","dispose","stop","removeEventListener","_dispatchTick","timestamp","dispatchEvent","CustomEvent","bubbles","_setRunning","_setSuspended","hidden","visibilityState","_reducedGate","matches","_clearHandle","_resolveScheduler","_requestFrame","start","options","repeat","reset","pause","resume","_frame","g","globalThis","requestAnimationFrame","cancelAnimationFrame","request","cb","cancel","handle","query","gen","registered","handleClick","Element","triggerElement","closest","rafId","getAttribute","RafCtor","customElements","get","rafElement","getElementById","preventDefault","hasAccessorOnPrototype","proto","Object","getPrototypeOf","descriptor","getOwnPropertyDescriptor","undefined","set","Raf","HTMLElement","wcBindable","inputs","attribute","observedAttributes","_core","_trigger","_connectedCallbackPromise","_internals","_initInternals","_wireStates","d","debugStates","states","attachInternals","internals","add","delete","map","toStates","entries","debug","hasAttribute","on","toggleAttribute","connectedCallbackPromise","once","setAttribute","removeAttribute","attr","trim","parsed","Number","isFinite","String","manual","attributeChangedCallback","_oldValue","newValue","trigger","connectedCallback","element","declaration","input","prototype","hasOwnProperty","call","record","upgradeProperties","style","display","disconnectedCallback","registry","define","registerComponents"],"mappings":"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"}
|
package/dist/index.d.ts
CHANGED
|
@@ -91,6 +91,8 @@ interface WcsRafInputs {
|
|
|
91
91
|
once: boolean;
|
|
92
92
|
repeat: number;
|
|
93
93
|
manual: boolean;
|
|
94
|
+
/** "pause" でだけ prefers-reduced-motion ゲートが効く。未知値は "run" 扱い */
|
|
95
|
+
reducedMotion: string;
|
|
94
96
|
trigger: boolean;
|
|
95
97
|
}
|
|
96
98
|
interface WcsRafCoreCommands {
|
|
@@ -110,7 +112,7 @@ interface WcsRafCommands {
|
|
|
110
112
|
resume(): void;
|
|
111
113
|
}
|
|
112
114
|
|
|
113
|
-
declare function bootstrapRaf(userConfig?: IWritableConfig): void;
|
|
115
|
+
declare function bootstrapRaf(userConfig?: IWritableConfig, registry?: CustomElementRegistry): void;
|
|
114
116
|
|
|
115
117
|
declare function getConfig(): IConfig;
|
|
116
118
|
|
|
@@ -135,6 +137,19 @@ interface RafScheduler {
|
|
|
135
137
|
request(callback: (timestamp: number) => void): unknown;
|
|
136
138
|
cancel(handle: unknown): void;
|
|
137
139
|
}
|
|
140
|
+
/**
|
|
141
|
+
* Injectable matchMedia pair for the `prefers-reduced-motion` gate. The
|
|
142
|
+
* default resolves `globalThis.matchMedia` at call time; tests inject a fake
|
|
143
|
+
* whose `matches` and `change` dispatch they control directly (happy-dom's
|
|
144
|
+
* MQL change delivery is not reliable enough to drive the gate transitions
|
|
145
|
+
* a 100/97 coverage target needs).
|
|
146
|
+
*/
|
|
147
|
+
interface RafMediaQuery {
|
|
148
|
+
readonly matches: boolean;
|
|
149
|
+
addEventListener(type: "change", listener: () => void): void;
|
|
150
|
+
removeEventListener(type: "change", listener: () => void): void;
|
|
151
|
+
}
|
|
152
|
+
type RafMatchMedia = (query: string) => RafMediaQuery;
|
|
138
153
|
/**
|
|
139
154
|
* Headless requestAnimationFrame primitive — `TimerCore`'s sibling with the
|
|
140
155
|
* time source swapped from `setInterval` (a period) to rAF (the browser's
|
|
@@ -167,6 +182,16 @@ interface RafScheduler {
|
|
|
167
182
|
* started intent) stays true while `suspended` reports that delivery is
|
|
168
183
|
* actually stopped. `suspended` is only meaningful after `observe()` has
|
|
169
184
|
* subscribed to `visibilitychange`; without a document it stays false.
|
|
185
|
+
* - **`suspended` has two causes**: `running && (hidden || reducedGate)`.
|
|
186
|
+
* The second cause is the opt-in `prefers-reduced-motion` gate
|
|
187
|
+
* (`reducedMotion === "pause"` while the media query matches —
|
|
188
|
+
* docs/a11y-design.md §6). It is deliberately NOT a `pause()` reuse:
|
|
189
|
+
* `_paused` is user intent (cleared by `start()`/`stop()`), and mixing an
|
|
190
|
+
* environment condition into it would let `resume()` override the OS
|
|
191
|
+
* setting. Unlike visibility — where the browser itself stops delivering
|
|
192
|
+
* frames — the reduced gate is enforced by this core: gate ON cancels the
|
|
193
|
+
* armed frame, gate OFF re-arms with a dt=0 boundary (G3, the same shape
|
|
194
|
+
* as a visibility interruption).
|
|
170
195
|
* - **No `error` surface.** rAF has no persistent failure mode; on a platform
|
|
171
196
|
* without it, `start()` is a silent no-op (never-throw, resize precedent).
|
|
172
197
|
*/
|
|
@@ -188,12 +213,17 @@ declare class RafCore extends EventTarget {
|
|
|
188
213
|
private _repeat;
|
|
189
214
|
private _runStartTick;
|
|
190
215
|
private _visibilityDoc;
|
|
191
|
-
|
|
216
|
+
private _reducedMotion;
|
|
217
|
+
private _mql;
|
|
218
|
+
private _injectedMatchMedia;
|
|
219
|
+
constructor(target?: EventTarget, scheduler?: RafScheduler, matchMedia?: RafMatchMedia);
|
|
192
220
|
get tick(): number;
|
|
193
221
|
get elapsed(): number;
|
|
194
222
|
get dt(): number;
|
|
195
223
|
get running(): boolean;
|
|
196
224
|
get suspended(): boolean;
|
|
225
|
+
get reducedMotion(): "run" | "pause";
|
|
226
|
+
set reducedMotion(value: "run" | "pause");
|
|
197
227
|
get ready(): Promise<void>;
|
|
198
228
|
observe(): Promise<void>;
|
|
199
229
|
dispose(): void;
|
|
@@ -201,6 +231,9 @@ declare class RafCore extends EventTarget {
|
|
|
201
231
|
private _setRunning;
|
|
202
232
|
private _setSuspended;
|
|
203
233
|
private _updateSuspended;
|
|
234
|
+
private _reducedGate;
|
|
235
|
+
private _onReducedMotionChange;
|
|
236
|
+
private _applyReducedGate;
|
|
204
237
|
start(options?: RafStartOptions): void;
|
|
205
238
|
stop(): void;
|
|
206
239
|
reset(): void;
|
|
@@ -209,6 +242,7 @@ declare class RafCore extends EventTarget {
|
|
|
209
242
|
private _frame;
|
|
210
243
|
private _onVisibilityChange;
|
|
211
244
|
private _resolveScheduler;
|
|
245
|
+
private _resolveMatchMedia;
|
|
212
246
|
private _requestFrame;
|
|
213
247
|
private _clearHandle;
|
|
214
248
|
}
|
|
@@ -216,6 +250,7 @@ declare class RafCore extends EventTarget {
|
|
|
216
250
|
declare class Raf extends HTMLElement {
|
|
217
251
|
static hasConnectedCallbackPromise: boolean;
|
|
218
252
|
static wcBindable: IWcBindable;
|
|
253
|
+
static get observedAttributes(): string[];
|
|
219
254
|
private _core;
|
|
220
255
|
private _trigger;
|
|
221
256
|
private _connectedCallbackPromise;
|
|
@@ -231,6 +266,9 @@ declare class Raf extends HTMLElement {
|
|
|
231
266
|
set repeat(value: number);
|
|
232
267
|
get manual(): boolean;
|
|
233
268
|
set manual(value: boolean);
|
|
269
|
+
get reducedMotion(): "run" | "pause";
|
|
270
|
+
set reducedMotion(value: string);
|
|
271
|
+
attributeChangedCallback(name: string, _oldValue: string | null, newValue: string | null): void;
|
|
234
272
|
get tick(): number;
|
|
235
273
|
get elapsed(): number;
|
|
236
274
|
get dt(): number;
|
package/dist/index.esm.js
CHANGED
|
@@ -81,6 +81,16 @@ function setConfig(partialConfig) {
|
|
|
81
81
|
* started intent) stays true while `suspended` reports that delivery is
|
|
82
82
|
* actually stopped. `suspended` is only meaningful after `observe()` has
|
|
83
83
|
* subscribed to `visibilitychange`; without a document it stays false.
|
|
84
|
+
* - **`suspended` has two causes**: `running && (hidden || reducedGate)`.
|
|
85
|
+
* The second cause is the opt-in `prefers-reduced-motion` gate
|
|
86
|
+
* (`reducedMotion === "pause"` while the media query matches —
|
|
87
|
+
* docs/a11y-design.md §6). It is deliberately NOT a `pause()` reuse:
|
|
88
|
+
* `_paused` is user intent (cleared by `start()`/`stop()`), and mixing an
|
|
89
|
+
* environment condition into it would let `resume()` override the OS
|
|
90
|
+
* setting. Unlike visibility — where the browser itself stops delivering
|
|
91
|
+
* frames — the reduced gate is enforced by this core: gate ON cancels the
|
|
92
|
+
* armed frame, gate OFF re-arms with a dt=0 boundary (G3, the same shape
|
|
93
|
+
* as a visibility interruption).
|
|
84
94
|
* - **No `error` surface.** rAF has no persistent failure mode; on a platform
|
|
85
95
|
* without it, `start()` is a silent no-op (never-throw, resize precedent).
|
|
86
96
|
*/
|
|
@@ -148,10 +158,20 @@ class RafCore extends EventTarget {
|
|
|
148
158
|
// and released in dispose(). Null before observe() or in non-DOM
|
|
149
159
|
// environments — `suspended` then simply stays false.
|
|
150
160
|
_visibilityDoc = null;
|
|
151
|
-
|
|
161
|
+
// The reduced-motion policy ("run" = ignore the preference, the default)
|
|
162
|
+
// and the media query subscribed in observe() / released in dispose().
|
|
163
|
+
// The live `change` subscription is MANDATORY, not an optimization: with a
|
|
164
|
+
// start-time check only, a loop started while reduce is active would sit
|
|
165
|
+
// running=true with no armed frame and no way to ever notice the
|
|
166
|
+
// preference clearing — a permanent wedge (docs/a11y-design.md §6-2).
|
|
167
|
+
_reducedMotion = "run";
|
|
168
|
+
_mql = null;
|
|
169
|
+
_injectedMatchMedia;
|
|
170
|
+
constructor(target, scheduler, matchMedia) {
|
|
152
171
|
super();
|
|
153
172
|
this._target = target ?? this;
|
|
154
173
|
this._injectedScheduler = scheduler ?? null;
|
|
174
|
+
this._injectedMatchMedia = matchMedia ?? null;
|
|
155
175
|
}
|
|
156
176
|
get tick() {
|
|
157
177
|
return this._tick;
|
|
@@ -168,6 +188,17 @@ class RafCore extends EventTarget {
|
|
|
168
188
|
get suspended() {
|
|
169
189
|
return this._suspended;
|
|
170
190
|
}
|
|
191
|
+
get reducedMotion() {
|
|
192
|
+
return this._reducedMotion;
|
|
193
|
+
}
|
|
194
|
+
set reducedMotion(value) {
|
|
195
|
+
// ポリシー変更はゲート入力の変化(MQL change と同じ扱い)。値の正規化
|
|
196
|
+
// (未知 → "run")は Shell の担当で、Core は正規化済みの 2 値だけを受ける。
|
|
197
|
+
if (this._reducedMotion === value)
|
|
198
|
+
return;
|
|
199
|
+
this._reducedMotion = value;
|
|
200
|
+
this._applyReducedGate();
|
|
201
|
+
}
|
|
171
202
|
// SSR readiness (§3.8): resolves after the first probe. There is nothing to
|
|
172
203
|
// probe, so this is an already-resolved promise.
|
|
173
204
|
get ready() {
|
|
@@ -190,6 +221,25 @@ class RafCore extends EventTarget {
|
|
|
190
221
|
// common visible-at-observe case dispatches nothing.
|
|
191
222
|
this._updateSuspended();
|
|
192
223
|
}
|
|
224
|
+
if (this._mql === null) {
|
|
225
|
+
const matchMedia = this._resolveMatchMedia();
|
|
226
|
+
if (matchMedia !== null) {
|
|
227
|
+
// never-throw(view-transition の ViewTransitionCore と同じ先例):
|
|
228
|
+
// 変な UA の matchMedia 例外で observe() 全体を殺さない。
|
|
229
|
+
try {
|
|
230
|
+
const mql = matchMedia("(prefers-reduced-motion: reduce)");
|
|
231
|
+
mql.addEventListener("change", this._onReducedMotionChange);
|
|
232
|
+
this._mql = mql;
|
|
233
|
+
// 購読時点の preference を反映する(visibility の同期と同じ理由:
|
|
234
|
+
// reduce 中に observe された場合、次の change を待つと偽の
|
|
235
|
+
// suspended=false を報告し、アーム済みフレームも生き残る)。
|
|
236
|
+
this._applyReducedGate();
|
|
237
|
+
}
|
|
238
|
+
catch {
|
|
239
|
+
this._mql = null;
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
}
|
|
193
243
|
return this._ready;
|
|
194
244
|
}
|
|
195
245
|
dispose() {
|
|
@@ -199,6 +249,10 @@ class RafCore extends EventTarget {
|
|
|
199
249
|
this._visibilityDoc.removeEventListener("visibilitychange", this._onVisibilityChange);
|
|
200
250
|
this._visibilityDoc = null;
|
|
201
251
|
}
|
|
252
|
+
if (this._mql !== null) {
|
|
253
|
+
this._mql.removeEventListener("change", this._onReducedMotionChange);
|
|
254
|
+
this._mql = null;
|
|
255
|
+
}
|
|
202
256
|
}
|
|
203
257
|
// --- State setters with event dispatch ---
|
|
204
258
|
_dispatchTick(timestamp) {
|
|
@@ -231,8 +285,41 @@ class RafCore extends EventTarget {
|
|
|
231
285
|
}));
|
|
232
286
|
}
|
|
233
287
|
_updateSuspended() {
|
|
288
|
+
// suspended の 2 原因: visibility と reduced-motion ゲート(クラスコメント参照)
|
|
234
289
|
const hidden = this._visibilityDoc !== null && this._visibilityDoc.visibilityState === "hidden";
|
|
235
|
-
this._setSuspended(this._running && hidden);
|
|
290
|
+
this._setSuspended(this._running && (hidden || this._reducedGate()));
|
|
291
|
+
}
|
|
292
|
+
// The reduced gate is active only when the author opted in ("pause") AND
|
|
293
|
+
// the subscribed media query currently matches. Before observe() — or
|
|
294
|
+
// without matchMedia — there is no subscription and the gate stays open.
|
|
295
|
+
_reducedGate() {
|
|
296
|
+
return this._reducedMotion === "pause" && this._mql !== null && this._mql.matches;
|
|
297
|
+
}
|
|
298
|
+
_onReducedMotionChange = () => {
|
|
299
|
+
this._applyReducedGate();
|
|
300
|
+
};
|
|
301
|
+
// Reflect the current gate value into the run state. Unlike visibility —
|
|
302
|
+
// where the browser itself stops delivering frames and the armed handle can
|
|
303
|
+
// stay put — the reduced gate is enforced here: ON cancels the armed frame
|
|
304
|
+
// (through _clearHandle, so the generation guard also invalidates an
|
|
305
|
+
// in-flight callback), OFF re-arms exactly one loop with a dt=0 interruption
|
|
306
|
+
// boundary (G3). The `_handle === null` check keeps a redundant change event
|
|
307
|
+
// from stacking a second loop; the re-arm is a no-op while paused-by-user
|
|
308
|
+
// (`_running` false) or already armed.
|
|
309
|
+
_applyReducedGate() {
|
|
310
|
+
if (this._running) {
|
|
311
|
+
if (this._reducedGate()) {
|
|
312
|
+
this._clearHandle();
|
|
313
|
+
}
|
|
314
|
+
else if (this._handle === null) {
|
|
315
|
+
this._lastTs = null;
|
|
316
|
+
const scheduler = this._resolveScheduler();
|
|
317
|
+
if (scheduler !== null) {
|
|
318
|
+
this._requestFrame(scheduler);
|
|
319
|
+
}
|
|
320
|
+
}
|
|
321
|
+
}
|
|
322
|
+
this._updateSuspended();
|
|
236
323
|
}
|
|
237
324
|
// --- Public API ---
|
|
238
325
|
start(options = {}) {
|
|
@@ -285,6 +372,10 @@ class RafCore extends EventTarget {
|
|
|
285
372
|
// re-entrant listener already scheduled the run for us.
|
|
286
373
|
if (!this._running || this._handle !== null)
|
|
287
374
|
return;
|
|
375
|
+
// reduce ゲート中の start(): running=true / suspended=true のまま非アーム。
|
|
376
|
+
// ゲート解除は MQL change → _applyReducedGate() が再アームする(§6-2)。
|
|
377
|
+
if (this._reducedGate())
|
|
378
|
+
return;
|
|
288
379
|
this._requestFrame(scheduler);
|
|
289
380
|
}
|
|
290
381
|
stop() {
|
|
@@ -335,6 +426,9 @@ class RafCore extends EventTarget {
|
|
|
335
426
|
// _setRunning(true) above.
|
|
336
427
|
if (!this._running || this._handle !== null)
|
|
337
428
|
return;
|
|
429
|
+
// reduce ゲート中は非アーム(start() と同じ)
|
|
430
|
+
if (this._reducedGate())
|
|
431
|
+
return;
|
|
338
432
|
this._requestFrame(scheduler);
|
|
339
433
|
}
|
|
340
434
|
// --- Internal ---
|
|
@@ -377,7 +471,13 @@ class RafCore extends EventTarget {
|
|
|
377
471
|
// second frame loop. The generation guard cannot catch this: a tail
|
|
378
472
|
// request here would capture the restart's own — current — generation
|
|
379
473
|
// and produce a second equally-valid loop).
|
|
380
|
-
|
|
474
|
+
//
|
|
475
|
+
// The reduced-gate check matters here too: a tick listener may have
|
|
476
|
+
// flipped the policy during the dispatch above. _applyReducedGate() ran
|
|
477
|
+
// then, but inside a frame `_handle` is already null (cleared on entry),
|
|
478
|
+
// so its _clearHandle() was a no-op and did NOT bump the generation —
|
|
479
|
+
// without this check the tail would happily re-arm through the gate.
|
|
480
|
+
if (this._running && this._handle === null && !this._reducedGate()) {
|
|
381
481
|
const scheduler = this._resolveScheduler();
|
|
382
482
|
if (scheduler !== null) {
|
|
383
483
|
this._requestFrame(scheduler);
|
|
@@ -413,6 +513,18 @@ class RafCore extends EventTarget {
|
|
|
413
513
|
}
|
|
414
514
|
return this._globalScheduler;
|
|
415
515
|
}
|
|
516
|
+
_resolveMatchMedia() {
|
|
517
|
+
if (this._injectedMatchMedia !== null)
|
|
518
|
+
return this._injectedMatchMedia;
|
|
519
|
+
const g = globalThis;
|
|
520
|
+
// §3.7: availability is checked at call time (observe() may be called in
|
|
521
|
+
// SSR pre-pass or a worker, where matchMedia is absent — the gate then
|
|
522
|
+
// simply never engages).
|
|
523
|
+
if (typeof g.matchMedia !== "function") {
|
|
524
|
+
return null;
|
|
525
|
+
}
|
|
526
|
+
return (query) => g.matchMedia(query);
|
|
527
|
+
}
|
|
416
528
|
// Arm the next frame (§3.4). The callback closes over the generation
|
|
417
529
|
// current at request time and re-checks it against the live `_gen` when the
|
|
418
530
|
// frame arrives; a callback that outlived its run bails here. See the
|
|
@@ -534,9 +646,13 @@ class Raf extends HTMLElement {
|
|
|
534
646
|
{ name: "once", attribute: "once" },
|
|
535
647
|
{ name: "repeat", attribute: "repeat" },
|
|
536
648
|
{ name: "manual", attribute: "manual" },
|
|
649
|
+
{ name: "reducedMotion", attribute: "reduced-motion" },
|
|
537
650
|
{ name: "trigger" },
|
|
538
651
|
],
|
|
539
652
|
};
|
|
653
|
+
static get observedAttributes() {
|
|
654
|
+
return ["reduced-motion"];
|
|
655
|
+
}
|
|
540
656
|
_core;
|
|
541
657
|
_trigger = false;
|
|
542
658
|
_connectedCallbackPromise = Promise.resolve();
|
|
@@ -640,6 +756,22 @@ class Raf extends HTMLElement {
|
|
|
640
756
|
this.removeAttribute("manual");
|
|
641
757
|
}
|
|
642
758
|
}
|
|
759
|
+
get reducedMotion() {
|
|
760
|
+
return this._core.reducedMotion;
|
|
761
|
+
}
|
|
762
|
+
set reducedMotion(value) {
|
|
763
|
+
// 属性へミラーし、attributeChangedCallback が正規化して Core へ届ける
|
|
764
|
+
this.setAttribute("reduced-motion", value);
|
|
765
|
+
}
|
|
766
|
+
attributeChangedCallback(name, _oldValue, newValue) {
|
|
767
|
+
if (name === "reduced-motion") {
|
|
768
|
+
// 未知値・属性なしは既定 "run" へ正規化(view-transition の setter 慣行)。
|
|
769
|
+
// once/repeat と違い start 時の遅延読みでは足りない — ポリシーは実行中の
|
|
770
|
+
// ループにも効く(reduce 中の付け外しがゲートの付け外し)ため、変更時に
|
|
771
|
+
// Core へ届ける。
|
|
772
|
+
this._core.reducedMotion = newValue === "pause" ? "pause" : "run";
|
|
773
|
+
}
|
|
774
|
+
}
|
|
643
775
|
// --- Core delegated getters ---
|
|
644
776
|
get tick() {
|
|
645
777
|
return this._core.tick;
|
|
@@ -725,17 +857,22 @@ class Raf extends HTMLElement {
|
|
|
725
857
|
}
|
|
726
858
|
}
|
|
727
859
|
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
860
|
+
/**
|
|
861
|
+
* Register this package's tags. Pass a scoped `CustomElementRegistry` to define
|
|
862
|
+
* them for a single shadow tree -- scoped registries do not inherit the global
|
|
863
|
+
* one, so a tree using one needs its own definitions.
|
|
864
|
+
*/
|
|
865
|
+
function registerComponents(registry = customElements) {
|
|
866
|
+
if (!registry.get(config.tagNames.raf)) {
|
|
867
|
+
registry.define(config.tagNames.raf, Raf);
|
|
731
868
|
}
|
|
732
869
|
}
|
|
733
870
|
|
|
734
|
-
function bootstrapRaf(userConfig) {
|
|
871
|
+
function bootstrapRaf(userConfig, registry) {
|
|
735
872
|
if (userConfig) {
|
|
736
873
|
setConfig(userConfig);
|
|
737
874
|
}
|
|
738
|
-
registerComponents();
|
|
875
|
+
registerComponents(registry);
|
|
739
876
|
}
|
|
740
877
|
|
|
741
878
|
export { RafCore, Raf as WcsRaf, bootstrapRaf, getConfig };
|
package/dist/index.esm.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.esm.js","sources":["../src/config.ts","../src/core/RafCore.ts","../src/autoTrigger.ts","../src/protocol/upgradeProperties.ts","../src/components/Raf.ts","../src/registerComponents.ts","../src/bootstrapRaf.ts"],"sourcesContent":["import { IConfig, IWritableConfig } from \"./types.js\";\n\ninterface IInternalConfig extends IConfig {\n autoTrigger: boolean;\n triggerAttribute: string;\n tagNames: {\n raf: string;\n };\n}\n\nconst _config: IInternalConfig = {\n autoTrigger: true,\n triggerAttribute: \"data-raftarget\",\n tagNames: {\n raf: \"wcs-raf\",\n },\n};\n\nfunction deepFreeze<T>(obj: T): T {\n if (obj === null || typeof obj !== \"object\") return obj;\n Object.freeze(obj);\n for (const key of Object.keys(obj)) {\n deepFreeze((obj as Record<string, unknown>)[key]);\n }\n return obj;\n}\n\nfunction deepClone<T>(obj: T): T {\n if (obj === null || typeof obj !== \"object\") return obj;\n const clone: Record<string, unknown> = {};\n for (const key of Object.keys(obj)) {\n clone[key] = deepClone((obj as Record<string, unknown>)[key]);\n }\n return clone as T;\n}\n\nlet frozenConfig: IConfig | null = null;\n\n// Internal-only live handle to the mutable config. NOT part of the public API\n// (deliberately absent from exports.ts) — it is exported solely so sibling\n// modules in this package can read current settings cheaply. External consumers\n// must use getConfig() (returns a deep-frozen snapshot) / setConfig(). Mutating\n// this object directly bypasses the frozenConfig cache and is unsupported.\nexport const config: IConfig = _config as IConfig;\n\nexport function getConfig(): IConfig {\n if (!frozenConfig) {\n frozenConfig = deepFreeze(deepClone(_config));\n }\n return frozenConfig;\n}\n\nexport function setConfig(partialConfig: IWritableConfig): void {\n if (typeof partialConfig.autoTrigger === \"boolean\") {\n _config.autoTrigger = partialConfig.autoTrigger;\n }\n if (typeof partialConfig.triggerAttribute === \"string\") {\n _config.triggerAttribute = partialConfig.triggerAttribute;\n }\n if (partialConfig.tagNames) {\n Object.assign(_config.tagNames, partialConfig.tagNames);\n }\n frozenConfig = null;\n}\n","import { IWcBindable } from \"../types.js\";\n\nexport interface RafStartOptions {\n repeat?: number;\n}\n\n/**\n * Injectable frame scheduler. The default resolves\n * `globalThis.requestAnimationFrame` / `cancelAnimationFrame` AT CALL TIME\n * (async-io-node-guidelines §3.7); tests inject a fake that pumps frames with\n * explicit timestamps (the `dt` contract is timestamp-derived, so tests must\n * control the clock, not just the callback order).\n *\n * Contract: `request()` MUST return a non-null handle. The core uses `null`\n * as its internal \"not armed\" sentinel, so a scheduler returning literal\n * `null` would silently corrupt the handle bookkeeping (re-entrancy guards\n * and cancel tracking). Native rAF returns a long, so this only concerns\n * custom scheduler injections — return a number, object, or any other\n * non-nullish token.\n */\nexport interface RafScheduler {\n request(callback: (timestamp: number) => void): unknown;\n cancel(handle: unknown): void;\n}\n\n/**\n * Headless requestAnimationFrame primitive — `TimerCore`'s sibling with the\n * time source swapped from `setInterval` (a period) to rAF (the browser's\n * rendering opportunity). Exposed through the wc-bindable protocol: it streams\n * `tick` (frame counter), `elapsed` (accumulated ACTIVE milliseconds), `dt`\n * (delta to the previous frame) and the `running` / `suspended` pair, and is\n * driven by the `start` / `stop` / `reset` / `pause` / `resume` commands.\n *\n * `tick` / `elapsed` / `dt` are all surfaced via the single `wcs-raf:tick`\n * event (read through getters, mirroring how FetchCore exposes value/status\n * from one `wcs-fetch:response` event).\n *\n * Contracts specific to this node (docs/raf-tag-design.md):\n *\n * - **dt describes continuous running only.** The first frame after `start()`,\n * `resume()`, or a visibility interruption reports `dt = 0` — a value that\n * spans an interruption never reaches observers. Like `suspended`, the\n * visibility boundary is only detected once observe() has subscribed to\n * `visibilitychange`; a headless setup that skips observe() will see the\n * raw spanning delta on the first frame after a hidden gap. There is\n * deliberately NO upper clamp: how to treat a slow frame is the consumer's\n * domain decision.\n * - **elapsed is Σdt (active time).** Because interruption-spanning deltas are\n * normalized to 0, summing dt yields exactly the time frames were actually\n * being delivered — no separate segment bookkeeping is needed, and hidden /\n * paused periods contribute nothing. Granularity is one frame: between\n * frames the getter returns the value as of the last tick.\n * - **running / suspended are a desired/actual pair** (the wakelock split): in\n * a hidden tab the browser delivers no frames at all, so `running` (the\n * started intent) stays true while `suspended` reports that delivery is\n * actually stopped. `suspended` is only meaningful after `observe()` has\n * subscribed to `visibilitychange`; without a document it stays false.\n * - **No `error` surface.** rAF has no persistent failure mode; on a platform\n * without it, `start()` is a silent no-op (never-throw, resize precedent).\n */\nexport class RafCore extends EventTarget {\n static wcBindable: IWcBindable = {\n protocol: \"wc-bindable\",\n version: 1,\n properties: [\n { name: \"tick\", event: \"wcs-raf:tick\", semantics: \"state\", getter: (e: Event) => (e as CustomEvent).detail.count },\n { name: \"elapsed\", event: \"wcs-raf:tick\", semantics: \"state\", getter: (e: Event) => (e as CustomEvent).detail.elapsed },\n { name: \"dt\", event: \"wcs-raf:tick\", semantics: \"state\", getter: (e: Event) => (e as CustomEvent).detail.dt },\n { name: \"running\", event: \"wcs-raf:running-changed\", semantics: \"state\" },\n { name: \"suspended\", event: \"wcs-raf:suspended-changed\", semantics: \"state\" },\n ],\n commands: [\n { name: \"start\" },\n { name: \"stop\" },\n { name: \"reset\" },\n { name: \"pause\" },\n { name: \"resume\" },\n ],\n };\n\n private _target: EventTarget;\n private _injectedScheduler: RafScheduler | null;\n private _handle: unknown = null;\n\n // Lazily-created wrapper around the global rAF pair, cached so the hot\n // frame-reschedule path (_frame, once per delivered frame) does not\n // allocate a new object + closures every call. `request`/`cancel` still\n // dereference `globalThis.requestAnimationFrame` / `cancelAnimationFrame`\n // live on every invocation (they are not snapshotted here), so call-time\n // resolution (§3.7) is unchanged — only the wrapper object itself is\n // reused once the global functions are first found present.\n private _globalScheduler: RafScheduler | null = null;\n\n // Generation guard (§3.4): a monotonic arming counter. Bumped when a run is\n // armed (start()/resume()), when an armed handle is cancelled\n // (_clearHandle()) and on dispose(). _requestFrame() captures the value in\n // each request's closure and drops the frame if it no longer matches the\n // live field when it fires. cancel() is best-effort against a non-compliant\n // scheduler; the captured generation is the guarantee — a stale callback can\n // neither mutate state, dispatch on a torn-down element, nor corrupt a\n // newer run's `_handle` bookkeeping. A live-field comparison (the previous\n // `_runGen` scheme) could not survive a dispose() → start() round trip: the\n // new start() re-synced the pair and let the stale callback through,\n // permanently doubling the frame loop.\n private _gen = 0;\n // SSR (§3.8): there is no asynchronous probe, so readiness is immediate.\n private _ready: Promise<void> = Promise.resolve();\n\n private _tick: number = 0;\n private _dt: number = 0;\n private _elapsed: number = 0;\n private _running: boolean = false;\n private _suspended: boolean = false;\n private _paused: boolean = false;\n\n // Timestamp of the previous frame within the current continuous run.\n // `null` means \"the next frame starts a run segment\": its dt is reported as\n // 0 (the G3 normalization). Cleared at start()/resume() and on every\n // visibilitychange (an interruption boundary).\n private _lastTs: number | null = null;\n\n // `_tick` value captured at the start of the current run. `repeat` counts\n // frames *per run*, so the stop condition compares against this baseline\n // rather than the cumulative `_tick` (which only resets on reset()).\n private _repeat: number = 0;\n private _runStartTick: number = 0;\n\n // The document whose visibility drives `suspended`, subscribed in observe()\n // and released in dispose(). Null before observe() or in non-DOM\n // environments — `suspended` then simply stays false.\n private _visibilityDoc: Document | null = null;\n\n constructor(target?: EventTarget, scheduler?: RafScheduler) {\n super();\n this._target = target ?? this;\n this._injectedScheduler = scheduler ?? null;\n }\n\n get tick(): number {\n return this._tick;\n }\n\n get elapsed(): number {\n return this._elapsed;\n }\n\n get dt(): number {\n return this._dt;\n }\n\n get running(): boolean {\n return this._running;\n }\n\n get suspended(): boolean {\n return this._suspended;\n }\n\n // SSR readiness (§3.8): resolves after the first probe. There is nothing to\n // probe, so this is an already-resolved promise.\n get ready(): Promise<void> {\n return this._ready;\n }\n\n // Lifecycle (§3.5). observe() establishes the one ambient subscription this\n // node has — `visibilitychange`, which drives the `suspended` output and the\n // dt=0 normalization across a hidden period. Idempotent; a no-op without a\n // document (SSR pre-pass, worker). dispose() tears everything down and bumps\n // the generation so a frame already queued cannot fire onto a torn-down\n // element.\n observe(): Promise<void> {\n if (this._visibilityDoc === null && typeof document !== \"undefined\") {\n this._visibilityDoc = document;\n document.addEventListener(\"visibilitychange\", this._onVisibilityChange);\n // Sync `suspended` to the visibility state at subscription time: with a\n // start()-before-observe() ordering (headless Core usage) the document\n // may already be hidden, and waiting for the next visibilitychange\n // would report suspended=false until then. Same-value guarded, so the\n // common visible-at-observe case dispatches nothing.\n this._updateSuspended();\n }\n return this._ready;\n }\n\n dispose(): void {\n this._gen++;\n this.stop();\n if (this._visibilityDoc !== null) {\n this._visibilityDoc.removeEventListener(\"visibilitychange\", this._onVisibilityChange);\n this._visibilityDoc = null;\n }\n }\n\n // --- State setters with event dispatch ---\n\n private _dispatchTick(timestamp: number): void {\n this._target.dispatchEvent(new CustomEvent(\"wcs-raf:tick\", {\n detail: { count: this._tick, elapsed: this._elapsed, dt: this._dt, timestamp },\n bubbles: true,\n }));\n }\n\n private _setRunning(running: boolean): void {\n if (this._running === running) return;\n this._running = running;\n this._target.dispatchEvent(new CustomEvent(\"wcs-raf:running-changed\", {\n detail: running,\n bubbles: true,\n }));\n // `suspended` is derived from (running && hidden), so every running\n // transition re-evaluates it: stop/pause drop a suspension, and a start()\n // inside an already-hidden tab reports it immediately (honestly: no frame\n // will arrive until the tab is visible again).\n this._updateSuspended();\n }\n\n private _setSuspended(suspended: boolean): void {\n if (this._suspended === suspended) return;\n this._suspended = suspended;\n this._target.dispatchEvent(new CustomEvent(\"wcs-raf:suspended-changed\", {\n detail: suspended,\n bubbles: true,\n }));\n }\n\n private _updateSuspended(): void {\n const hidden = this._visibilityDoc !== null && this._visibilityDoc.visibilityState === \"hidden\";\n this._setSuspended(this._running && hidden);\n }\n\n // --- Public API ---\n\n start(options: RafStartOptions = {}): void {\n // Idempotent while running: a redundant start() must not stack a second\n // frame loop (which would double the tick rate). Reconfiguring an active\n // run is done via stop() + start().\n if (this._running) return;\n\n // Resolve the platform API at call time (§3.7). Absent rAF (SSR pre-pass,\n // worker) makes start() a silent no-op — never-throw, and this node has no\n // error surface by design.\n const scheduler = this._resolveScheduler();\n if (scheduler === null) return;\n\n // start() begins a fresh run, so clear any lingering pause from a prior\n // pause()-without-resume(). Without this, the loop would run while _paused\n // stayed true, leaving pause() a no-op and letting resume() overwrite the\n // live handle (leak + double fire).\n this._paused = false;\n\n // `repeat` is per-run intent, NOT persistent configuration: every start()\n // re-establishes it from the options, defaulting to \"unlimited\" when\n // omitted. This keeps a bare start() after a bounded run from silently\n // inheriting the old bounds.\n this._repeat = (typeof options.repeat === \"number\" && options.repeat > 0) ? options.repeat : 0;\n\n // New arming generation (§3.4): invalidates any callback still in flight\n // from a previous run (e.g. one whose cancel() a non-compliant scheduler\n // ignored). Bumped BEFORE the running-changed dispatch below, so that a\n // re-entrant restart from a listener arms with the newest generation —\n // the re-entrancy guard then keeps this outer call from arming (and\n // bumping) on top of it.\n this._gen++;\n\n this._setRunning(true);\n // Baseline this run's per-run repeat counting (set after _setRunning so a\n // re-start of a completed bounded run fires the full N frames again).\n this._runStartTick = this._tick;\n // G3: the first frame of a run reports dt = 0.\n this._lastTs = null;\n\n // Re-entrancy guard: _setRunning(true) just dispatched running-changed\n // synchronously, and a listener may have changed the world from inside it.\n // - `!_running`: the listener called stop()/pause()/dispose(). Without\n // this check a \"ghost\" frame would still be scheduled for an\n // already-stopped run — it would either tick once while running stays\n // false, or leave an uncancellable handle behind.\n // - `_handle !== null`: the listener restarted the loop itself\n // (stop()→start()); the inner start() already armed the new run, and\n // requesting again here would overwrite `_handle` (losing the inner\n // handle, never cancelled) and stack a permanent second frame loop.\n // On the normal path `_handle` is always null here — every transition\n // to `_running === false` clears it — so non-null can only mean a\n // re-entrant listener already scheduled the run for us.\n if (!this._running || this._handle !== null) return;\n this._requestFrame(scheduler);\n }\n\n stop(): void {\n this._clearHandle();\n this._paused = false;\n this._setRunning(false);\n }\n\n reset(): void {\n this._clearHandle();\n this._paused = false;\n this._tick = 0;\n this._elapsed = 0;\n this._dt = 0;\n this._lastTs = null;\n this._setRunning(false);\n // Notify observers that the counter/elapsed/dt have returned to zero. The\n // notification is not a frame, so `timestamp` is 0 (see WcsRafTickDetail).\n this._dispatchTick(0);\n }\n\n pause(): void {\n // Pause only a live loop; a no-op otherwise so it composes safely with the\n // declarative lifecycle. Unlike stop(), it records `_paused` so resume()\n // can tell an intentional pause from a full stop. No elapsed bookkeeping\n // is needed: elapsed is Σdt, and the resume boundary's dt is 0.\n if (!this._running || this._paused) return;\n this._clearHandle();\n this._paused = true;\n this._setRunning(false);\n }\n\n resume(): void {\n if (!this._paused) return;\n const scheduler = this._resolveScheduler();\n if (scheduler === null) return;\n this._paused = false;\n // New arming generation (§3.4), bumped before the running-changed\n // dispatch for the same re-entrancy reason as start().\n this._gen++;\n this._setRunning(true);\n // G3: the first frame after a pause reports dt = 0 (elapsed therefore does\n // not count the paused period — the \"active time\" contract).\n this._lastTs = null;\n\n // Re-entrancy guard, for the same reasons as start() (see the comment\n // there): a running-changed listener may have synchronously stopped this\n // node — or restarted it, leaving `_handle` already armed — from inside\n // _setRunning(true) above.\n if (!this._running || this._handle !== null) return;\n this._requestFrame(scheduler);\n }\n\n // --- Internal ---\n\n private _frame = (timestamp: number): void => {\n // Reached only through _requestFrame's generation-checked closure (§3.4):\n // a stale callback — disposed, cancelled by a non-compliant scheduler, or\n // superseded by a newer run — never gets here.\n this._handle = null;\n\n // dt: delta to the previous frame within this continuous run; 0 when this\n // frame opens a segment (start/resume/visibility boundary — G3).\n const dt = this._lastTs === null ? 0 : timestamp - this._lastTs;\n this._lastTs = timestamp;\n\n this._tick++;\n this._dt = dt;\n this._elapsed += dt;\n this._dispatchTick(timestamp);\n\n // Auto-stop once this run has fired the requested number of frames\n // (repeat=0 runs forever). Counted per-run via `_runStartTick`, so a\n // re-start after a completed bounded run fires N frames again. `once` is\n // expressed by the Shell as repeat=1.\n //\n // The cleanup mirrors stop() exactly, because a tick listener may have\n // synchronously paused — or paused and resumed — DURING the final frame's\n // dispatch above. The run's budget is exhausted either way, so clear the\n // pause (a later resume() must be a no-op, not an N+1th frame) and cancel\n // any handle a re-entrant resume() armed (it would otherwise survive as a\n // ghost frame and tick past the budget). On the normal path both are\n // already clear (no-ops). A stop()→start() restart is NOT affected: the\n // new run re-baselines `_runStartTick`, so this branch is not taken.\n if (this._repeat > 0 && (this._tick - this._runStartTick) >= this._repeat) {\n this._clearHandle();\n this._paused = false;\n this._setRunning(false);\n return;\n }\n\n // Re-request the next frame — unless a tick listener stopped the loop\n // synchronously during the dispatch above, or already scheduled a new run\n // itself (a synchronous stop()→start() / pause()→resume() restart leaves\n // _handle non-null; re-requesting on top of it would stack a permanent\n // second frame loop. The generation guard cannot catch this: a tail\n // request here would capture the restart's own — current — generation\n // and produce a second equally-valid loop).\n if (this._running && this._handle === null) {\n const scheduler = this._resolveScheduler();\n if (scheduler !== null) {\n this._requestFrame(scheduler);\n }\n }\n };\n\n private _onVisibilityChange = (): void => {\n // Either direction is an interruption boundary: entering hidden means the\n // browser stops delivering frames, so the NEXT delivered frame must not\n // report a delta spanning the gap (G3). Clearing on the visible edge too\n // is belt-and-braces for a missed hidden event — the worst case is one\n // extra dt=0 frame.\n this._lastTs = null;\n this._updateSuspended();\n };\n\n private _resolveScheduler(): RafScheduler | null {\n if (this._injectedScheduler !== null) return this._injectedScheduler;\n const g = globalThis as unknown as {\n requestAnimationFrame?: (cb: (ts: number) => void) => unknown;\n cancelAnimationFrame?: (handle: unknown) => void;\n };\n // The availability check itself still runs on every call (§3.7: resolved\n // at call time, not cached across an absence/presence flip).\n if (typeof g.requestAnimationFrame !== \"function\" || typeof g.cancelAnimationFrame !== \"function\") {\n return null;\n }\n if (this._globalScheduler === null) {\n // `g` is just a typed alias for `globalThis` (not a snapshot), so these\n // closures keep dereferencing the live global functions even though the\n // wrapper object itself is created only once.\n this._globalScheduler = {\n request: (cb) => g.requestAnimationFrame!(cb),\n cancel: (handle) => g.cancelAnimationFrame!(handle),\n };\n }\n return this._globalScheduler;\n }\n\n // Arm the next frame (§3.4). The callback closes over the generation\n // current at request time and re-checks it against the live `_gen` when the\n // frame arrives; a callback that outlived its run bails here. See the\n // `_gen` field comment for why this must be a per-request capture and not a\n // live-field comparison.\n private _requestFrame(scheduler: RafScheduler): void {\n const gen = this._gen;\n this._handle = scheduler.request((timestamp: number) => {\n if (gen !== this._gen) return;\n this._frame(timestamp);\n });\n }\n\n private _clearHandle(): void {\n if (this._handle !== null) {\n this._resolveScheduler()?.cancel(this._handle);\n this._handle = null;\n // Invalidate the cancelled callback's captured generation as well:\n // cancel() is best-effort against a non-compliant scheduler, the\n // generation is the guarantee (§3.4).\n this._gen++;\n }\n }\n}\n","import { config } from \"./config.js\";\nimport type { Raf } from \"./components/Raf.js\";\n\nlet registered = false;\n\nfunction handleClick(event: Event): void {\n const target = event.target;\n if (!(target instanceof Element)) return;\n\n const triggerElement = target.closest<Element>(`[${config.triggerAttribute}]`);\n if (!triggerElement) return;\n\n const rafId = triggerElement.getAttribute(config.triggerAttribute);\n if (!rafId) return;\n\n // Resolve the registered constructor at call time instead of importing Raf\n // as a value. The value import created a components/Raf.ts ⇄ autoTrigger.ts\n // cycle (Raf.connectedCallback() calls registerAutoTrigger()). instanceof\n // against the customElements registry keeps the exact same identity guarantee\n // — only the registered <wcs-raf> class matches — without the import cycle.\n const RafCtor = customElements.get(config.tagNames.raf);\n const rafElement = document.getElementById(rafId);\n if (!RafCtor || !(rafElement instanceof RafCtor)) return;\n\n // Suppress the element's default action so a loop can start without\n // navigating. Intentional: do not attach data-raftarget to an element whose\n // default action you also want (real <a href> link, form-submit button) — it\n // will be cancelled. See README \"Optional DOM Triggering\".\n event.preventDefault();\n (rafElement as Raf).start();\n}\n\nexport function registerAutoTrigger(): void {\n if (registered) return;\n registered = true;\n document.addEventListener(\"click\", handleClick);\n}\n\nexport function unregisterAutoTrigger(): void {\n if (!registered) return;\n registered = false;\n document.removeEventListener(\"click\", handleClick);\n}\n","// ===========================================================================\n// AUTO-GENERATED FILE - DO NOT EDIT.\n// Generated from /protocol/upgrade-properties.ts by scripts/sync-protocol-types.mjs.\n// Run `node scripts/sync-protocol-types.mjs` after editing the source.\n// ===========================================================================\n\n// custom element の property upgrade — `static wcBindable.inputs` に宣言した入力のうち、\n// 要素が upgrade される前に代入された own データプロパティを取り込み直す。\n//\n// なぜ必要か:\n// 未定義タグの要素は素の HTMLElement なので、`el.url = \"...\"` は own データプロパティを作る。\n// upgrade 後にクラスの accessor が prototype へ入っても own プロパティが優先されるため、\n// setter は二度と呼ばれず、値は要素へ届かないまま消える(エラーも警告も出ない)。\n// 常にプロパティ代入を行う framework(Angular の `[prop]`、Lit の `.prop=`、\n// Solid の `prop:`、Vue の `.prop` 修飾子)× 遅延定義(autoloader / CDN / code-split)で\n// 常態的に起きる。docs/architecture-hardening/13-framework-adapter-binding-constraints.md §1.2。\n//\n// 安全側の判定:\n// own プロパティがあっても、prototype チェーンに accessor が無ければ「シャドウ」ではなく\n// その own プロパティ自体が正規の格納先なので触らない(public class field を壊さない)。\n//\n// SINGLE SOURCE OF TRUTH: edit only this file (/protocol/upgrade-properties.ts), then run\n// `node scripts/sync-protocol-types.mjs` to regenerate the per-package copies\n// (packages/<pkg>/src/protocol/upgradeProperties.ts). Those copies are generated — do not edit them.\nimport { IWcBindable } from \"./wcBindable.js\";\n\nfunction hasAccessorOnPrototype(target: object, name: string): boolean {\n let proto = Object.getPrototypeOf(target);\n while (proto !== null) {\n const descriptor = Object.getOwnPropertyDescriptor(proto, name);\n if (descriptor !== undefined) {\n return typeof descriptor.get === \"function\" || typeof descriptor.set === \"function\";\n }\n proto = Object.getPrototypeOf(proto);\n }\n return false;\n}\n\n/**\n * `connectedCallback` の先頭で呼ぶ。宣言済み input のうち upgrade 前の代入で\n * accessor をシャドウしている own プロパティを、delete → 再代入で setter に通し直す。\n *\n * - 冪等: 再代入は accessor を通るので own プロパティは残らず、2 回目以降は no-op。\n * - 宣言に `inputs` が無い要素、`wcBindable` を持たない要素では何もしない。\n * - 値の意味は変えない。今まで捨てられていた代入が届くようになる一方向の変化。\n */\nexport function upgradeProperties(element: object): void {\n const declaration = (element as { constructor?: { wcBindable?: IWcBindable } }).constructor?.wcBindable;\n const inputs = declaration?.inputs;\n if (inputs === undefined) return;\n for (const input of inputs) {\n const name = input.name;\n if (!Object.prototype.hasOwnProperty.call(element, name)) continue;\n if (!hasAccessorOnPrototype(element, name)) continue;\n const record = element as Record<string, unknown>;\n const value = record[name];\n delete record[name];\n record[name] = value;\n }\n}\n","import { config } from \"../config.js\";\nimport { IWcBindable } from \"../types.js\";\nimport { RafCore } from \"../core/RafCore.js\";\nimport { registerAutoTrigger } from \"../autoTrigger.js\";\nimport { upgradeProperties } from \"../protocol/upgradeProperties.js\";\n\nexport class Raf extends HTMLElement {\n static hasConnectedCallbackPromise = true;\n static wcBindable: IWcBindable = {\n ...RafCore.wcBindable,\n properties: [\n ...RafCore.wcBindable.properties,\n { name: \"trigger\", event: \"wcs-raf:trigger-changed\", semantics: \"state\" },\n ],\n // Shell-level settable surface. `attribute` is a purely descriptive hint\n // (per SPEC-extensions.md the binding core does not act on it) naming the\n // mirrored HTML attribute, matching <wcs-timer>. `trigger` is a momentary\n // command-property with no backing attribute, so it carries no hint.\n // `start` / `stop` / `reset` / `pause` / `resume` commands are inherited\n // from the Core above. Deliberately absent vs <wcs-timer>: `interval`\n // (rAF has no period) and `immediate` (the first frame already IS the\n // next rendering opportunity — no earlier meaningful moment exists).\n inputs: [\n { name: \"once\", attribute: \"once\" },\n { name: \"repeat\", attribute: \"repeat\" },\n { name: \"manual\", attribute: \"manual\" },\n { name: \"trigger\" },\n ],\n };\n\n private _core: RafCore;\n private _trigger: boolean = false;\n private _connectedCallbackPromise: Promise<void> = Promise.resolve();\n private _internals: ElementInternals | null = null;\n\n constructor() {\n super();\n this._core = new RafCore(this);\n this._internals = this._initInternals();\n this._wireStates({\n \"wcs-raf:running-changed\": (d) => ({ running: d === true }),\n \"wcs-raf:suspended-changed\": (d) => ({ suspended: d === true }),\n });\n }\n\n // CSS state reflection (:state()) — debug-only snapshot getter. NOT part of\n // wc-bindable (not a bind target); see README \"CSS styling with :state()\".\n // MUST NOT return the live CustomStateSet (that would let callers write\n // states from outside, defeating the point of :state() being read-only).\n get debugStates(): string[] {\n return this._internals ? [...this._internals.states] : [];\n }\n\n private _initInternals(): ElementInternals | null {\n // never-throw (async-io-node-guidelines.md §3.6): attachInternals is absent\n // in happy-dom / older environments, and pre-125 Chromium rejects\n // non-dashed state names from states.add() (probed and discarded here).\n // Either case silently disables reflection — the component still works,\n // it just doesn't expose :state() selectors.\n try {\n if (typeof this.attachInternals !== \"function\") return null;\n const internals = this.attachInternals();\n internals.states.add(\"wcs-probe\");\n internals.states.delete(\"wcs-probe\");\n return internals;\n } catch {\n return null;\n }\n }\n\n private _wireStates(map: Record<string, (detail: any) => Record<string, boolean>>): void {\n if (this._internals === null) return;\n const states = this._internals.states;\n for (const [event, toStates] of Object.entries(map)) {\n this.addEventListener(event, (e) => {\n const debug = this.hasAttribute(\"debug-states\");\n for (const [name, on] of Object.entries(toStates((e as CustomEvent).detail))) {\n try {\n if (on) { states.add(name); } else { states.delete(name); }\n } catch { /* never-throw */ }\n if (debug) this.toggleAttribute(`data-wcs-state-${name}`, on);\n }\n });\n }\n }\n\n // SSR (§4.1/§4.4): the Shell exposes the Core's readiness so a server-side\n // renderer can await the connect-time probe before snapshotting. There is no\n // async probe here (observe() resolves immediately), but the contract is\n // uniform across IO nodes.\n get connectedCallbackPromise(): Promise<void> {\n return this._connectedCallbackPromise;\n }\n\n // --- Attribute accessors ---\n\n get once(): boolean {\n return this.hasAttribute(\"once\");\n }\n\n set once(value: boolean) {\n if (value) {\n this.setAttribute(\"once\", \"\");\n } else {\n this.removeAttribute(\"once\");\n }\n }\n\n get repeat(): number {\n const attr = this.getAttribute(\"repeat\");\n if (attr === null || attr.trim() === \"\") return 0;\n // Strict parse via Number() (\"3px\" -> NaN, not 3), matching <wcs-timer>.\n // Normalise any non-positive / non-numeric value to 0 (= unlimited).\n const parsed = Number(attr);\n return (Number.isFinite(parsed) && parsed > 0) ? parsed : 0;\n }\n\n set repeat(value: number) {\n this.setAttribute(\"repeat\", String(value));\n }\n\n get manual(): boolean {\n return this.hasAttribute(\"manual\");\n }\n\n set manual(value: boolean) {\n if (value) {\n this.setAttribute(\"manual\", \"\");\n } else {\n this.removeAttribute(\"manual\");\n }\n }\n\n // --- Core delegated getters ---\n\n get tick(): number {\n return this._core.tick;\n }\n\n get elapsed(): number {\n return this._core.elapsed;\n }\n\n get dt(): number {\n return this._core.dt;\n }\n\n get running(): boolean {\n return this._core.running;\n }\n\n get suspended(): boolean {\n return this._core.suspended;\n }\n\n // --- Command property ---\n\n get trigger(): boolean {\n return this._trigger;\n }\n\n set trigger(value: boolean) {\n // Momentary command-property: a false→true write starts the loop. Mirrors\n // <wcs-timer>. Prefer the command-token protocol (`command.start:\n // $command.begin`) for state-driven starts; this exists mainly for the DOM\n // click trigger and simple boolean bindings.\n const v = !!value;\n if (v) {\n this._trigger = true;\n this.start();\n this._trigger = false;\n // The `trigger-changed` event reports the momentary flag returning to\n // false, i.e. that the trigger property *changed* — it is deliberately\n // not gated on whether start() actually began a new run (same contract\n // as <wcs-timer>).\n this.dispatchEvent(new CustomEvent(\"wcs-raf:trigger-changed\", {\n detail: false,\n bubbles: true,\n }));\n }\n }\n\n // --- Commands ---\n\n start(): void {\n // `once` is sugar for \"fire exactly one frame\": map it to repeat=1, but\n // let an explicit repeat attribute win when both are present.\n const repeat = this.repeat > 0 ? this.repeat : (this.once ? 1 : 0);\n this._core.start({ repeat });\n }\n\n stop(): void {\n this._core.stop();\n }\n\n reset(): void {\n this._core.reset();\n }\n\n pause(): void {\n this._core.pause();\n }\n\n resume(): void {\n this._core.resume();\n }\n\n // --- Lifecycle ---\n\n connectedCallback(): void {\n // upgrade 前に代入された input を取り込み直す(doc 13 §1.2 / Phase A1)\n upgradeProperties(this);\n this.style.display = \"none\";\n if (config.autoTrigger) {\n registerAutoTrigger();\n }\n // Establish monitoring (§3.5): observe() subscribes visibilitychange (the\n // `suspended` output) and resolves once ready; expose it as\n // connectedCallbackPromise for SSR. Note for SSR pages: an auto-started\n // frame loop keeps scheduling — prefer `manual` in server-rendered markup\n // (see README).\n this._connectedCallbackPromise = this._core.observe();\n if (!this.manual) {\n this.start();\n }\n }\n\n disconnectedCallback(): void {\n // dispose() stops the loop, releases the visibility subscription and bumps\n // the generation so a frame already queued cannot fire onto a disconnected\n // element (§3.5 / §4.4).\n this._core.dispose();\n }\n}\n","import { Raf } from \"./components/Raf.js\";\nimport { config } from \"./config.js\";\n\nexport function registerComponents(): void {\n if (!customElements.get(config.tagNames.raf)) {\n customElements.define(config.tagNames.raf, Raf);\n }\n}\n","import { setConfig } from \"./config.js\";\nimport { registerComponents } from \"./registerComponents.js\";\nimport { IWritableConfig } from \"./types.js\";\n\nexport function bootstrapRaf(userConfig?: IWritableConfig): void {\n if (userConfig) {\n setConfig(userConfig);\n }\n registerComponents();\n}\n"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.esm.js","sources":["../src/config.ts","../src/core/RafCore.ts","../src/autoTrigger.ts","../src/protocol/upgradeProperties.ts","../src/components/Raf.ts","../src/registerComponents.ts","../src/bootstrapRaf.ts"],"sourcesContent":["import { IConfig, IWritableConfig } from \"./types.js\";\n\ninterface IInternalConfig extends IConfig {\n autoTrigger: boolean;\n triggerAttribute: string;\n tagNames: {\n raf: string;\n };\n}\n\nconst _config: IInternalConfig = {\n autoTrigger: true,\n triggerAttribute: \"data-raftarget\",\n tagNames: {\n raf: \"wcs-raf\",\n },\n};\n\nfunction deepFreeze<T>(obj: T): T {\n if (obj === null || typeof obj !== \"object\") return obj;\n Object.freeze(obj);\n for (const key of Object.keys(obj)) {\n deepFreeze((obj as Record<string, unknown>)[key]);\n }\n return obj;\n}\n\nfunction deepClone<T>(obj: T): T {\n if (obj === null || typeof obj !== \"object\") return obj;\n const clone: Record<string, unknown> = {};\n for (const key of Object.keys(obj)) {\n clone[key] = deepClone((obj as Record<string, unknown>)[key]);\n }\n return clone as T;\n}\n\nlet frozenConfig: IConfig | null = null;\n\n// Internal-only live handle to the mutable config. NOT part of the public API\n// (deliberately absent from exports.ts) — it is exported solely so sibling\n// modules in this package can read current settings cheaply. External consumers\n// must use getConfig() (returns a deep-frozen snapshot) / setConfig(). Mutating\n// this object directly bypasses the frozenConfig cache and is unsupported.\nexport const config: IConfig = _config as IConfig;\n\nexport function getConfig(): IConfig {\n if (!frozenConfig) {\n frozenConfig = deepFreeze(deepClone(_config));\n }\n return frozenConfig;\n}\n\nexport function setConfig(partialConfig: IWritableConfig): void {\n if (typeof partialConfig.autoTrigger === \"boolean\") {\n _config.autoTrigger = partialConfig.autoTrigger;\n }\n if (typeof partialConfig.triggerAttribute === \"string\") {\n _config.triggerAttribute = partialConfig.triggerAttribute;\n }\n if (partialConfig.tagNames) {\n Object.assign(_config.tagNames, partialConfig.tagNames);\n }\n frozenConfig = null;\n}\n","import { IWcBindable } from \"../types.js\";\n\nexport interface RafStartOptions {\n repeat?: number;\n}\n\n/**\n * Injectable frame scheduler. The default resolves\n * `globalThis.requestAnimationFrame` / `cancelAnimationFrame` AT CALL TIME\n * (async-io-node-guidelines §3.7); tests inject a fake that pumps frames with\n * explicit timestamps (the `dt` contract is timestamp-derived, so tests must\n * control the clock, not just the callback order).\n *\n * Contract: `request()` MUST return a non-null handle. The core uses `null`\n * as its internal \"not armed\" sentinel, so a scheduler returning literal\n * `null` would silently corrupt the handle bookkeeping (re-entrancy guards\n * and cancel tracking). Native rAF returns a long, so this only concerns\n * custom scheduler injections — return a number, object, or any other\n * non-nullish token.\n */\nexport interface RafScheduler {\n request(callback: (timestamp: number) => void): unknown;\n cancel(handle: unknown): void;\n}\n\n/**\n * Injectable matchMedia pair for the `prefers-reduced-motion` gate. The\n * default resolves `globalThis.matchMedia` at call time; tests inject a fake\n * whose `matches` and `change` dispatch they control directly (happy-dom's\n * MQL change delivery is not reliable enough to drive the gate transitions\n * a 100/97 coverage target needs).\n */\nexport interface RafMediaQuery {\n readonly matches: boolean;\n addEventListener(type: \"change\", listener: () => void): void;\n removeEventListener(type: \"change\", listener: () => void): void;\n}\n\nexport type RafMatchMedia = (query: string) => RafMediaQuery;\n\n/**\n * Headless requestAnimationFrame primitive — `TimerCore`'s sibling with the\n * time source swapped from `setInterval` (a period) to rAF (the browser's\n * rendering opportunity). Exposed through the wc-bindable protocol: it streams\n * `tick` (frame counter), `elapsed` (accumulated ACTIVE milliseconds), `dt`\n * (delta to the previous frame) and the `running` / `suspended` pair, and is\n * driven by the `start` / `stop` / `reset` / `pause` / `resume` commands.\n *\n * `tick` / `elapsed` / `dt` are all surfaced via the single `wcs-raf:tick`\n * event (read through getters, mirroring how FetchCore exposes value/status\n * from one `wcs-fetch:response` event).\n *\n * Contracts specific to this node (docs/raf-tag-design.md):\n *\n * - **dt describes continuous running only.** The first frame after `start()`,\n * `resume()`, or a visibility interruption reports `dt = 0` — a value that\n * spans an interruption never reaches observers. Like `suspended`, the\n * visibility boundary is only detected once observe() has subscribed to\n * `visibilitychange`; a headless setup that skips observe() will see the\n * raw spanning delta on the first frame after a hidden gap. There is\n * deliberately NO upper clamp: how to treat a slow frame is the consumer's\n * domain decision.\n * - **elapsed is Σdt (active time).** Because interruption-spanning deltas are\n * normalized to 0, summing dt yields exactly the time frames were actually\n * being delivered — no separate segment bookkeeping is needed, and hidden /\n * paused periods contribute nothing. Granularity is one frame: between\n * frames the getter returns the value as of the last tick.\n * - **running / suspended are a desired/actual pair** (the wakelock split): in\n * a hidden tab the browser delivers no frames at all, so `running` (the\n * started intent) stays true while `suspended` reports that delivery is\n * actually stopped. `suspended` is only meaningful after `observe()` has\n * subscribed to `visibilitychange`; without a document it stays false.\n * - **`suspended` has two causes**: `running && (hidden || reducedGate)`.\n * The second cause is the opt-in `prefers-reduced-motion` gate\n * (`reducedMotion === \"pause\"` while the media query matches —\n * docs/a11y-design.md §6). It is deliberately NOT a `pause()` reuse:\n * `_paused` is user intent (cleared by `start()`/`stop()`), and mixing an\n * environment condition into it would let `resume()` override the OS\n * setting. Unlike visibility — where the browser itself stops delivering\n * frames — the reduced gate is enforced by this core: gate ON cancels the\n * armed frame, gate OFF re-arms with a dt=0 boundary (G3, the same shape\n * as a visibility interruption).\n * - **No `error` surface.** rAF has no persistent failure mode; on a platform\n * without it, `start()` is a silent no-op (never-throw, resize precedent).\n */\nexport class RafCore extends EventTarget {\n static wcBindable: IWcBindable = {\n protocol: \"wc-bindable\",\n version: 1,\n properties: [\n { name: \"tick\", event: \"wcs-raf:tick\", semantics: \"state\", getter: (e: Event) => (e as CustomEvent).detail.count },\n { name: \"elapsed\", event: \"wcs-raf:tick\", semantics: \"state\", getter: (e: Event) => (e as CustomEvent).detail.elapsed },\n { name: \"dt\", event: \"wcs-raf:tick\", semantics: \"state\", getter: (e: Event) => (e as CustomEvent).detail.dt },\n { name: \"running\", event: \"wcs-raf:running-changed\", semantics: \"state\" },\n { name: \"suspended\", event: \"wcs-raf:suspended-changed\", semantics: \"state\" },\n ],\n commands: [\n { name: \"start\" },\n { name: \"stop\" },\n { name: \"reset\" },\n { name: \"pause\" },\n { name: \"resume\" },\n ],\n };\n\n private _target: EventTarget;\n private _injectedScheduler: RafScheduler | null;\n private _handle: unknown = null;\n\n // Lazily-created wrapper around the global rAF pair, cached so the hot\n // frame-reschedule path (_frame, once per delivered frame) does not\n // allocate a new object + closures every call. `request`/`cancel` still\n // dereference `globalThis.requestAnimationFrame` / `cancelAnimationFrame`\n // live on every invocation (they are not snapshotted here), so call-time\n // resolution (§3.7) is unchanged — only the wrapper object itself is\n // reused once the global functions are first found present.\n private _globalScheduler: RafScheduler | null = null;\n\n // Generation guard (§3.4): a monotonic arming counter. Bumped when a run is\n // armed (start()/resume()), when an armed handle is cancelled\n // (_clearHandle()) and on dispose(). _requestFrame() captures the value in\n // each request's closure and drops the frame if it no longer matches the\n // live field when it fires. cancel() is best-effort against a non-compliant\n // scheduler; the captured generation is the guarantee — a stale callback can\n // neither mutate state, dispatch on a torn-down element, nor corrupt a\n // newer run's `_handle` bookkeeping. A live-field comparison (the previous\n // `_runGen` scheme) could not survive a dispose() → start() round trip: the\n // new start() re-synced the pair and let the stale callback through,\n // permanently doubling the frame loop.\n private _gen = 0;\n // SSR (§3.8): there is no asynchronous probe, so readiness is immediate.\n private _ready: Promise<void> = Promise.resolve();\n\n private _tick: number = 0;\n private _dt: number = 0;\n private _elapsed: number = 0;\n private _running: boolean = false;\n private _suspended: boolean = false;\n private _paused: boolean = false;\n\n // Timestamp of the previous frame within the current continuous run.\n // `null` means \"the next frame starts a run segment\": its dt is reported as\n // 0 (the G3 normalization). Cleared at start()/resume() and on every\n // visibilitychange (an interruption boundary).\n private _lastTs: number | null = null;\n\n // `_tick` value captured at the start of the current run. `repeat` counts\n // frames *per run*, so the stop condition compares against this baseline\n // rather than the cumulative `_tick` (which only resets on reset()).\n private _repeat: number = 0;\n private _runStartTick: number = 0;\n\n // The document whose visibility drives `suspended`, subscribed in observe()\n // and released in dispose(). Null before observe() or in non-DOM\n // environments — `suspended` then simply stays false.\n private _visibilityDoc: Document | null = null;\n\n // The reduced-motion policy (\"run\" = ignore the preference, the default)\n // and the media query subscribed in observe() / released in dispose().\n // The live `change` subscription is MANDATORY, not an optimization: with a\n // start-time check only, a loop started while reduce is active would sit\n // running=true with no armed frame and no way to ever notice the\n // preference clearing — a permanent wedge (docs/a11y-design.md §6-2).\n private _reducedMotion: \"run\" | \"pause\" = \"run\";\n private _mql: RafMediaQuery | null = null;\n private _injectedMatchMedia: RafMatchMedia | null;\n\n constructor(target?: EventTarget, scheduler?: RafScheduler, matchMedia?: RafMatchMedia) {\n super();\n this._target = target ?? this;\n this._injectedScheduler = scheduler ?? null;\n this._injectedMatchMedia = matchMedia ?? null;\n }\n\n get tick(): number {\n return this._tick;\n }\n\n get elapsed(): number {\n return this._elapsed;\n }\n\n get dt(): number {\n return this._dt;\n }\n\n get running(): boolean {\n return this._running;\n }\n\n get suspended(): boolean {\n return this._suspended;\n }\n\n get reducedMotion(): \"run\" | \"pause\" {\n return this._reducedMotion;\n }\n\n set reducedMotion(value: \"run\" | \"pause\") {\n // ポリシー変更はゲート入力の変化(MQL change と同じ扱い)。値の正規化\n // (未知 → \"run\")は Shell の担当で、Core は正規化済みの 2 値だけを受ける。\n if (this._reducedMotion === value) return;\n this._reducedMotion = value;\n this._applyReducedGate();\n }\n\n // SSR readiness (§3.8): resolves after the first probe. There is nothing to\n // probe, so this is an already-resolved promise.\n get ready(): Promise<void> {\n return this._ready;\n }\n\n // Lifecycle (§3.5). observe() establishes the one ambient subscription this\n // node has — `visibilitychange`, which drives the `suspended` output and the\n // dt=0 normalization across a hidden period. Idempotent; a no-op without a\n // document (SSR pre-pass, worker). dispose() tears everything down and bumps\n // the generation so a frame already queued cannot fire onto a torn-down\n // element.\n observe(): Promise<void> {\n if (this._visibilityDoc === null && typeof document !== \"undefined\") {\n this._visibilityDoc = document;\n document.addEventListener(\"visibilitychange\", this._onVisibilityChange);\n // Sync `suspended` to the visibility state at subscription time: with a\n // start()-before-observe() ordering (headless Core usage) the document\n // may already be hidden, and waiting for the next visibilitychange\n // would report suspended=false until then. Same-value guarded, so the\n // common visible-at-observe case dispatches nothing.\n this._updateSuspended();\n }\n if (this._mql === null) {\n const matchMedia = this._resolveMatchMedia();\n if (matchMedia !== null) {\n // never-throw(view-transition の ViewTransitionCore と同じ先例):\n // 変な UA の matchMedia 例外で observe() 全体を殺さない。\n try {\n const mql = matchMedia(\"(prefers-reduced-motion: reduce)\");\n mql.addEventListener(\"change\", this._onReducedMotionChange);\n this._mql = mql;\n // 購読時点の preference を反映する(visibility の同期と同じ理由:\n // reduce 中に observe された場合、次の change を待つと偽の\n // suspended=false を報告し、アーム済みフレームも生き残る)。\n this._applyReducedGate();\n } catch {\n this._mql = null;\n }\n }\n }\n return this._ready;\n }\n\n dispose(): void {\n this._gen++;\n this.stop();\n if (this._visibilityDoc !== null) {\n this._visibilityDoc.removeEventListener(\"visibilitychange\", this._onVisibilityChange);\n this._visibilityDoc = null;\n }\n if (this._mql !== null) {\n this._mql.removeEventListener(\"change\", this._onReducedMotionChange);\n this._mql = null;\n }\n }\n\n // --- State setters with event dispatch ---\n\n private _dispatchTick(timestamp: number): void {\n this._target.dispatchEvent(new CustomEvent(\"wcs-raf:tick\", {\n detail: { count: this._tick, elapsed: this._elapsed, dt: this._dt, timestamp },\n bubbles: true,\n }));\n }\n\n private _setRunning(running: boolean): void {\n if (this._running === running) return;\n this._running = running;\n this._target.dispatchEvent(new CustomEvent(\"wcs-raf:running-changed\", {\n detail: running,\n bubbles: true,\n }));\n // `suspended` is derived from (running && hidden), so every running\n // transition re-evaluates it: stop/pause drop a suspension, and a start()\n // inside an already-hidden tab reports it immediately (honestly: no frame\n // will arrive until the tab is visible again).\n this._updateSuspended();\n }\n\n private _setSuspended(suspended: boolean): void {\n if (this._suspended === suspended) return;\n this._suspended = suspended;\n this._target.dispatchEvent(new CustomEvent(\"wcs-raf:suspended-changed\", {\n detail: suspended,\n bubbles: true,\n }));\n }\n\n private _updateSuspended(): void {\n // suspended の 2 原因: visibility と reduced-motion ゲート(クラスコメント参照)\n const hidden = this._visibilityDoc !== null && this._visibilityDoc.visibilityState === \"hidden\";\n this._setSuspended(this._running && (hidden || this._reducedGate()));\n }\n\n // The reduced gate is active only when the author opted in (\"pause\") AND\n // the subscribed media query currently matches. Before observe() — or\n // without matchMedia — there is no subscription and the gate stays open.\n private _reducedGate(): boolean {\n return this._reducedMotion === \"pause\" && this._mql !== null && this._mql.matches;\n }\n\n private _onReducedMotionChange = (): void => {\n this._applyReducedGate();\n };\n\n // Reflect the current gate value into the run state. Unlike visibility —\n // where the browser itself stops delivering frames and the armed handle can\n // stay put — the reduced gate is enforced here: ON cancels the armed frame\n // (through _clearHandle, so the generation guard also invalidates an\n // in-flight callback), OFF re-arms exactly one loop with a dt=0 interruption\n // boundary (G3). The `_handle === null` check keeps a redundant change event\n // from stacking a second loop; the re-arm is a no-op while paused-by-user\n // (`_running` false) or already armed.\n private _applyReducedGate(): void {\n if (this._running) {\n if (this._reducedGate()) {\n this._clearHandle();\n } else if (this._handle === null) {\n this._lastTs = null;\n const scheduler = this._resolveScheduler();\n if (scheduler !== null) {\n this._requestFrame(scheduler);\n }\n }\n }\n this._updateSuspended();\n }\n\n // --- Public API ---\n\n start(options: RafStartOptions = {}): void {\n // Idempotent while running: a redundant start() must not stack a second\n // frame loop (which would double the tick rate). Reconfiguring an active\n // run is done via stop() + start().\n if (this._running) return;\n\n // Resolve the platform API at call time (§3.7). Absent rAF (SSR pre-pass,\n // worker) makes start() a silent no-op — never-throw, and this node has no\n // error surface by design.\n const scheduler = this._resolveScheduler();\n if (scheduler === null) return;\n\n // start() begins a fresh run, so clear any lingering pause from a prior\n // pause()-without-resume(). Without this, the loop would run while _paused\n // stayed true, leaving pause() a no-op and letting resume() overwrite the\n // live handle (leak + double fire).\n this._paused = false;\n\n // `repeat` is per-run intent, NOT persistent configuration: every start()\n // re-establishes it from the options, defaulting to \"unlimited\" when\n // omitted. This keeps a bare start() after a bounded run from silently\n // inheriting the old bounds.\n this._repeat = (typeof options.repeat === \"number\" && options.repeat > 0) ? options.repeat : 0;\n\n // New arming generation (§3.4): invalidates any callback still in flight\n // from a previous run (e.g. one whose cancel() a non-compliant scheduler\n // ignored). Bumped BEFORE the running-changed dispatch below, so that a\n // re-entrant restart from a listener arms with the newest generation —\n // the re-entrancy guard then keeps this outer call from arming (and\n // bumping) on top of it.\n this._gen++;\n\n this._setRunning(true);\n // Baseline this run's per-run repeat counting (set after _setRunning so a\n // re-start of a completed bounded run fires the full N frames again).\n this._runStartTick = this._tick;\n // G3: the first frame of a run reports dt = 0.\n this._lastTs = null;\n\n // Re-entrancy guard: _setRunning(true) just dispatched running-changed\n // synchronously, and a listener may have changed the world from inside it.\n // - `!_running`: the listener called stop()/pause()/dispose(). Without\n // this check a \"ghost\" frame would still be scheduled for an\n // already-stopped run — it would either tick once while running stays\n // false, or leave an uncancellable handle behind.\n // - `_handle !== null`: the listener restarted the loop itself\n // (stop()→start()); the inner start() already armed the new run, and\n // requesting again here would overwrite `_handle` (losing the inner\n // handle, never cancelled) and stack a permanent second frame loop.\n // On the normal path `_handle` is always null here — every transition\n // to `_running === false` clears it — so non-null can only mean a\n // re-entrant listener already scheduled the run for us.\n if (!this._running || this._handle !== null) return;\n // reduce ゲート中の start(): running=true / suspended=true のまま非アーム。\n // ゲート解除は MQL change → _applyReducedGate() が再アームする(§6-2)。\n if (this._reducedGate()) return;\n this._requestFrame(scheduler);\n }\n\n stop(): void {\n this._clearHandle();\n this._paused = false;\n this._setRunning(false);\n }\n\n reset(): void {\n this._clearHandle();\n this._paused = false;\n this._tick = 0;\n this._elapsed = 0;\n this._dt = 0;\n this._lastTs = null;\n this._setRunning(false);\n // Notify observers that the counter/elapsed/dt have returned to zero. The\n // notification is not a frame, so `timestamp` is 0 (see WcsRafTickDetail).\n this._dispatchTick(0);\n }\n\n pause(): void {\n // Pause only a live loop; a no-op otherwise so it composes safely with the\n // declarative lifecycle. Unlike stop(), it records `_paused` so resume()\n // can tell an intentional pause from a full stop. No elapsed bookkeeping\n // is needed: elapsed is Σdt, and the resume boundary's dt is 0.\n if (!this._running || this._paused) return;\n this._clearHandle();\n this._paused = true;\n this._setRunning(false);\n }\n\n resume(): void {\n if (!this._paused) return;\n const scheduler = this._resolveScheduler();\n if (scheduler === null) return;\n this._paused = false;\n // New arming generation (§3.4), bumped before the running-changed\n // dispatch for the same re-entrancy reason as start().\n this._gen++;\n this._setRunning(true);\n // G3: the first frame after a pause reports dt = 0 (elapsed therefore does\n // not count the paused period — the \"active time\" contract).\n this._lastTs = null;\n\n // Re-entrancy guard, for the same reasons as start() (see the comment\n // there): a running-changed listener may have synchronously stopped this\n // node — or restarted it, leaving `_handle` already armed — from inside\n // _setRunning(true) above.\n if (!this._running || this._handle !== null) return;\n // reduce ゲート中は非アーム(start() と同じ)\n if (this._reducedGate()) return;\n this._requestFrame(scheduler);\n }\n\n // --- Internal ---\n\n private _frame = (timestamp: number): void => {\n // Reached only through _requestFrame's generation-checked closure (§3.4):\n // a stale callback — disposed, cancelled by a non-compliant scheduler, or\n // superseded by a newer run — never gets here.\n this._handle = null;\n\n // dt: delta to the previous frame within this continuous run; 0 when this\n // frame opens a segment (start/resume/visibility boundary — G3).\n const dt = this._lastTs === null ? 0 : timestamp - this._lastTs;\n this._lastTs = timestamp;\n\n this._tick++;\n this._dt = dt;\n this._elapsed += dt;\n this._dispatchTick(timestamp);\n\n // Auto-stop once this run has fired the requested number of frames\n // (repeat=0 runs forever). Counted per-run via `_runStartTick`, so a\n // re-start after a completed bounded run fires N frames again. `once` is\n // expressed by the Shell as repeat=1.\n //\n // The cleanup mirrors stop() exactly, because a tick listener may have\n // synchronously paused — or paused and resumed — DURING the final frame's\n // dispatch above. The run's budget is exhausted either way, so clear the\n // pause (a later resume() must be a no-op, not an N+1th frame) and cancel\n // any handle a re-entrant resume() armed (it would otherwise survive as a\n // ghost frame and tick past the budget). On the normal path both are\n // already clear (no-ops). A stop()→start() restart is NOT affected: the\n // new run re-baselines `_runStartTick`, so this branch is not taken.\n if (this._repeat > 0 && (this._tick - this._runStartTick) >= this._repeat) {\n this._clearHandle();\n this._paused = false;\n this._setRunning(false);\n return;\n }\n\n // Re-request the next frame — unless a tick listener stopped the loop\n // synchronously during the dispatch above, or already scheduled a new run\n // itself (a synchronous stop()→start() / pause()→resume() restart leaves\n // _handle non-null; re-requesting on top of it would stack a permanent\n // second frame loop. The generation guard cannot catch this: a tail\n // request here would capture the restart's own — current — generation\n // and produce a second equally-valid loop).\n //\n // The reduced-gate check matters here too: a tick listener may have\n // flipped the policy during the dispatch above. _applyReducedGate() ran\n // then, but inside a frame `_handle` is already null (cleared on entry),\n // so its _clearHandle() was a no-op and did NOT bump the generation —\n // without this check the tail would happily re-arm through the gate.\n if (this._running && this._handle === null && !this._reducedGate()) {\n const scheduler = this._resolveScheduler();\n if (scheduler !== null) {\n this._requestFrame(scheduler);\n }\n }\n };\n\n private _onVisibilityChange = (): void => {\n // Either direction is an interruption boundary: entering hidden means the\n // browser stops delivering frames, so the NEXT delivered frame must not\n // report a delta spanning the gap (G3). Clearing on the visible edge too\n // is belt-and-braces for a missed hidden event — the worst case is one\n // extra dt=0 frame.\n this._lastTs = null;\n this._updateSuspended();\n };\n\n private _resolveScheduler(): RafScheduler | null {\n if (this._injectedScheduler !== null) return this._injectedScheduler;\n const g = globalThis as unknown as {\n requestAnimationFrame?: (cb: (ts: number) => void) => unknown;\n cancelAnimationFrame?: (handle: unknown) => void;\n };\n // The availability check itself still runs on every call (§3.7: resolved\n // at call time, not cached across an absence/presence flip).\n if (typeof g.requestAnimationFrame !== \"function\" || typeof g.cancelAnimationFrame !== \"function\") {\n return null;\n }\n if (this._globalScheduler === null) {\n // `g` is just a typed alias for `globalThis` (not a snapshot), so these\n // closures keep dereferencing the live global functions even though the\n // wrapper object itself is created only once.\n this._globalScheduler = {\n request: (cb) => g.requestAnimationFrame!(cb),\n cancel: (handle) => g.cancelAnimationFrame!(handle),\n };\n }\n return this._globalScheduler;\n }\n\n private _resolveMatchMedia(): RafMatchMedia | null {\n if (this._injectedMatchMedia !== null) return this._injectedMatchMedia;\n const g = globalThis as unknown as {\n matchMedia?: (query: string) => RafMediaQuery;\n };\n // §3.7: availability is checked at call time (observe() may be called in\n // SSR pre-pass or a worker, where matchMedia is absent — the gate then\n // simply never engages).\n if (typeof g.matchMedia !== \"function\") {\n return null;\n }\n return (query) => g.matchMedia!(query);\n }\n\n // Arm the next frame (§3.4). The callback closes over the generation\n // current at request time and re-checks it against the live `_gen` when the\n // frame arrives; a callback that outlived its run bails here. See the\n // `_gen` field comment for why this must be a per-request capture and not a\n // live-field comparison.\n private _requestFrame(scheduler: RafScheduler): void {\n const gen = this._gen;\n this._handle = scheduler.request((timestamp: number) => {\n if (gen !== this._gen) return;\n this._frame(timestamp);\n });\n }\n\n private _clearHandle(): void {\n if (this._handle !== null) {\n this._resolveScheduler()?.cancel(this._handle);\n this._handle = null;\n // Invalidate the cancelled callback's captured generation as well:\n // cancel() is best-effort against a non-compliant scheduler, the\n // generation is the guarantee (§3.4).\n this._gen++;\n }\n }\n}\n","import { config } from \"./config.js\";\nimport type { Raf } from \"./components/Raf.js\";\n\nlet registered = false;\n\nfunction handleClick(event: Event): void {\n const target = event.target;\n if (!(target instanceof Element)) return;\n\n const triggerElement = target.closest<Element>(`[${config.triggerAttribute}]`);\n if (!triggerElement) return;\n\n const rafId = triggerElement.getAttribute(config.triggerAttribute);\n if (!rafId) return;\n\n // Resolve the registered constructor at call time instead of importing Raf\n // as a value. The value import created a components/Raf.ts ⇄ autoTrigger.ts\n // cycle (Raf.connectedCallback() calls registerAutoTrigger()). instanceof\n // against the customElements registry keeps the exact same identity guarantee\n // — only the registered <wcs-raf> class matches — without the import cycle.\n const RafCtor = customElements.get(config.tagNames.raf);\n const rafElement = document.getElementById(rafId);\n if (!RafCtor || !(rafElement instanceof RafCtor)) return;\n\n // Suppress the element's default action so a loop can start without\n // navigating. Intentional: do not attach data-raftarget to an element whose\n // default action you also want (real <a href> link, form-submit button) — it\n // will be cancelled. See README \"Optional DOM Triggering\".\n event.preventDefault();\n (rafElement as Raf).start();\n}\n\nexport function registerAutoTrigger(): void {\n if (registered) return;\n registered = true;\n document.addEventListener(\"click\", handleClick);\n}\n\nexport function unregisterAutoTrigger(): void {\n if (!registered) return;\n registered = false;\n document.removeEventListener(\"click\", handleClick);\n}\n","// ===========================================================================\n// AUTO-GENERATED FILE - DO NOT EDIT.\n// Generated from /protocol/upgrade-properties.ts by scripts/sync-protocol-types.mjs.\n// Run `node scripts/sync-protocol-types.mjs` after editing the source.\n// ===========================================================================\n\n// custom element の property upgrade — `static wcBindable.inputs` に宣言した入力のうち、\n// 要素が upgrade される前に代入された own データプロパティを取り込み直す。\n//\n// なぜ必要か:\n// 未定義タグの要素は素の HTMLElement なので、`el.url = \"...\"` は own データプロパティを作る。\n// upgrade 後にクラスの accessor が prototype へ入っても own プロパティが優先されるため、\n// setter は二度と呼ばれず、値は要素へ届かないまま消える(エラーも警告も出ない)。\n// 常にプロパティ代入を行う framework(Angular の `[prop]`、Lit の `.prop=`、\n// Solid の `prop:`、Vue の `.prop` 修飾子)× 遅延定義(autoloader / CDN / code-split)で\n// 常態的に起きる。docs/architecture-hardening/13-framework-adapter-binding-constraints.md §1.2。\n//\n// 安全側の判定:\n// own プロパティがあっても、prototype チェーンに accessor が無ければ「シャドウ」ではなく\n// その own プロパティ自体が正規の格納先なので触らない(public class field を壊さない)。\n//\n// SINGLE SOURCE OF TRUTH: edit only this file (/protocol/upgrade-properties.ts), then run\n// `node scripts/sync-protocol-types.mjs` to regenerate the per-package copies\n// (packages/<pkg>/src/protocol/upgradeProperties.ts). Those copies are generated — do not edit them.\nimport { IWcBindable } from \"./wcBindable.js\";\n\nfunction hasAccessorOnPrototype(target: object, name: string): boolean {\n let proto = Object.getPrototypeOf(target);\n while (proto !== null) {\n const descriptor = Object.getOwnPropertyDescriptor(proto, name);\n if (descriptor !== undefined) {\n return typeof descriptor.get === \"function\" || typeof descriptor.set === \"function\";\n }\n proto = Object.getPrototypeOf(proto);\n }\n return false;\n}\n\n/**\n * `connectedCallback` の先頭で呼ぶ。宣言済み input のうち upgrade 前の代入で\n * accessor をシャドウしている own プロパティを、delete → 再代入で setter に通し直す。\n *\n * - 冪等: 再代入は accessor を通るので own プロパティは残らず、2 回目以降は no-op。\n * - 宣言に `inputs` が無い要素、`wcBindable` を持たない要素では何もしない。\n * - 値の意味は変えない。今まで捨てられていた代入が届くようになる一方向の変化。\n */\nexport function upgradeProperties(element: object): void {\n const declaration = (element as { constructor?: { wcBindable?: IWcBindable } }).constructor?.wcBindable;\n const inputs = declaration?.inputs;\n if (inputs === undefined) return;\n for (const input of inputs) {\n const name = input.name;\n if (!Object.prototype.hasOwnProperty.call(element, name)) continue;\n if (!hasAccessorOnPrototype(element, name)) continue;\n const record = element as Record<string, unknown>;\n const value = record[name];\n delete record[name];\n record[name] = value;\n }\n}\n","import { config } from \"../config.js\";\nimport { IWcBindable } from \"../types.js\";\nimport { RafCore } from \"../core/RafCore.js\";\nimport { registerAutoTrigger } from \"../autoTrigger.js\";\nimport { upgradeProperties } from \"../protocol/upgradeProperties.js\";\n\nexport class Raf extends HTMLElement {\n static hasConnectedCallbackPromise = true;\n static wcBindable: IWcBindable = {\n ...RafCore.wcBindable,\n properties: [\n ...RafCore.wcBindable.properties,\n { name: \"trigger\", event: \"wcs-raf:trigger-changed\", semantics: \"state\" },\n ],\n // Shell-level settable surface. `attribute` is a purely descriptive hint\n // (per SPEC-extensions.md the binding core does not act on it) naming the\n // mirrored HTML attribute, matching <wcs-timer>. `trigger` is a momentary\n // command-property with no backing attribute, so it carries no hint.\n // `start` / `stop` / `reset` / `pause` / `resume` commands are inherited\n // from the Core above. Deliberately absent vs <wcs-timer>: `interval`\n // (rAF has no period) and `immediate` (the first frame already IS the\n // next rendering opportunity — no earlier meaningful moment exists).\n inputs: [\n { name: \"once\", attribute: \"once\" },\n { name: \"repeat\", attribute: \"repeat\" },\n { name: \"manual\", attribute: \"manual\" },\n { name: \"reducedMotion\", attribute: \"reduced-motion\" },\n { name: \"trigger\" },\n ],\n };\n\n static get observedAttributes(): string[] {\n return [\"reduced-motion\"];\n }\n\n private _core: RafCore;\n private _trigger: boolean = false;\n private _connectedCallbackPromise: Promise<void> = Promise.resolve();\n private _internals: ElementInternals | null = null;\n\n constructor() {\n super();\n this._core = new RafCore(this);\n this._internals = this._initInternals();\n this._wireStates({\n \"wcs-raf:running-changed\": (d) => ({ running: d === true }),\n \"wcs-raf:suspended-changed\": (d) => ({ suspended: d === true }),\n });\n }\n\n // CSS state reflection (:state()) — debug-only snapshot getter. NOT part of\n // wc-bindable (not a bind target); see README \"CSS styling with :state()\".\n // MUST NOT return the live CustomStateSet (that would let callers write\n // states from outside, defeating the point of :state() being read-only).\n get debugStates(): string[] {\n return this._internals ? [...this._internals.states] : [];\n }\n\n private _initInternals(): ElementInternals | null {\n // never-throw (async-io-node-guidelines.md §3.6): attachInternals is absent\n // in happy-dom / older environments, and pre-125 Chromium rejects\n // non-dashed state names from states.add() (probed and discarded here).\n // Either case silently disables reflection — the component still works,\n // it just doesn't expose :state() selectors.\n try {\n if (typeof this.attachInternals !== \"function\") return null;\n const internals = this.attachInternals();\n internals.states.add(\"wcs-probe\");\n internals.states.delete(\"wcs-probe\");\n return internals;\n } catch {\n return null;\n }\n }\n\n private _wireStates(map: Record<string, (detail: any) => Record<string, boolean>>): void {\n if (this._internals === null) return;\n const states = this._internals.states;\n for (const [event, toStates] of Object.entries(map)) {\n this.addEventListener(event, (e) => {\n const debug = this.hasAttribute(\"debug-states\");\n for (const [name, on] of Object.entries(toStates((e as CustomEvent).detail))) {\n try {\n if (on) { states.add(name); } else { states.delete(name); }\n } catch { /* never-throw */ }\n if (debug) this.toggleAttribute(`data-wcs-state-${name}`, on);\n }\n });\n }\n }\n\n // SSR (§4.1/§4.4): the Shell exposes the Core's readiness so a server-side\n // renderer can await the connect-time probe before snapshotting. There is no\n // async probe here (observe() resolves immediately), but the contract is\n // uniform across IO nodes.\n get connectedCallbackPromise(): Promise<void> {\n return this._connectedCallbackPromise;\n }\n\n // --- Attribute accessors ---\n\n get once(): boolean {\n return this.hasAttribute(\"once\");\n }\n\n set once(value: boolean) {\n if (value) {\n this.setAttribute(\"once\", \"\");\n } else {\n this.removeAttribute(\"once\");\n }\n }\n\n get repeat(): number {\n const attr = this.getAttribute(\"repeat\");\n if (attr === null || attr.trim() === \"\") return 0;\n // Strict parse via Number() (\"3px\" -> NaN, not 3), matching <wcs-timer>.\n // Normalise any non-positive / non-numeric value to 0 (= unlimited).\n const parsed = Number(attr);\n return (Number.isFinite(parsed) && parsed > 0) ? parsed : 0;\n }\n\n set repeat(value: number) {\n this.setAttribute(\"repeat\", String(value));\n }\n\n get manual(): boolean {\n return this.hasAttribute(\"manual\");\n }\n\n set manual(value: boolean) {\n if (value) {\n this.setAttribute(\"manual\", \"\");\n } else {\n this.removeAttribute(\"manual\");\n }\n }\n\n get reducedMotion(): \"run\" | \"pause\" {\n return this._core.reducedMotion;\n }\n\n set reducedMotion(value: string) {\n // 属性へミラーし、attributeChangedCallback が正規化して Core へ届ける\n this.setAttribute(\"reduced-motion\", value);\n }\n\n attributeChangedCallback(name: string, _oldValue: string | null, newValue: string | null): void {\n if (name === \"reduced-motion\") {\n // 未知値・属性なしは既定 \"run\" へ正規化(view-transition の setter 慣行)。\n // once/repeat と違い start 時の遅延読みでは足りない — ポリシーは実行中の\n // ループにも効く(reduce 中の付け外しがゲートの付け外し)ため、変更時に\n // Core へ届ける。\n this._core.reducedMotion = newValue === \"pause\" ? \"pause\" : \"run\";\n }\n }\n\n // --- Core delegated getters ---\n\n get tick(): number {\n return this._core.tick;\n }\n\n get elapsed(): number {\n return this._core.elapsed;\n }\n\n get dt(): number {\n return this._core.dt;\n }\n\n get running(): boolean {\n return this._core.running;\n }\n\n get suspended(): boolean {\n return this._core.suspended;\n }\n\n // --- Command property ---\n\n get trigger(): boolean {\n return this._trigger;\n }\n\n set trigger(value: boolean) {\n // Momentary command-property: a false→true write starts the loop. Mirrors\n // <wcs-timer>. Prefer the command-token protocol (`command.start:\n // $command.begin`) for state-driven starts; this exists mainly for the DOM\n // click trigger and simple boolean bindings.\n const v = !!value;\n if (v) {\n this._trigger = true;\n this.start();\n this._trigger = false;\n // The `trigger-changed` event reports the momentary flag returning to\n // false, i.e. that the trigger property *changed* — it is deliberately\n // not gated on whether start() actually began a new run (same contract\n // as <wcs-timer>).\n this.dispatchEvent(new CustomEvent(\"wcs-raf:trigger-changed\", {\n detail: false,\n bubbles: true,\n }));\n }\n }\n\n // --- Commands ---\n\n start(): void {\n // `once` is sugar for \"fire exactly one frame\": map it to repeat=1, but\n // let an explicit repeat attribute win when both are present.\n const repeat = this.repeat > 0 ? this.repeat : (this.once ? 1 : 0);\n this._core.start({ repeat });\n }\n\n stop(): void {\n this._core.stop();\n }\n\n reset(): void {\n this._core.reset();\n }\n\n pause(): void {\n this._core.pause();\n }\n\n resume(): void {\n this._core.resume();\n }\n\n // --- Lifecycle ---\n\n connectedCallback(): void {\n // upgrade 前に代入された input を取り込み直す(doc 13 §1.2 / Phase A1)\n upgradeProperties(this);\n this.style.display = \"none\";\n if (config.autoTrigger) {\n registerAutoTrigger();\n }\n // Establish monitoring (§3.5): observe() subscribes visibilitychange (the\n // `suspended` output) and resolves once ready; expose it as\n // connectedCallbackPromise for SSR. Note for SSR pages: an auto-started\n // frame loop keeps scheduling — prefer `manual` in server-rendered markup\n // (see README).\n this._connectedCallbackPromise = this._core.observe();\n if (!this.manual) {\n this.start();\n }\n }\n\n disconnectedCallback(): void {\n // dispose() stops the loop, releases the visibility subscription and bumps\n // the generation so a frame already queued cannot fire onto a disconnected\n // element (§3.5 / §4.4).\n this._core.dispose();\n }\n}\n","import { Raf } from \"./components/Raf.js\";\nimport { config } from \"./config.js\";\n\n/**\n * Register this package's tags. Pass a scoped `CustomElementRegistry` to define\n * them for a single shadow tree -- scoped registries do not inherit the global\n * one, so a tree using one needs its own definitions.\n */\nexport function registerComponents(registry: CustomElementRegistry = customElements): void {\n if (!registry.get(config.tagNames.raf)) {\n registry.define(config.tagNames.raf, Raf);\n }\n}\n","import { setConfig } from \"./config.js\";\nimport { registerComponents } from \"./registerComponents.js\";\nimport { IWritableConfig } from \"./types.js\";\n\nexport function bootstrapRaf(userConfig?: IWritableConfig, registry?: CustomElementRegistry): void {\n if (userConfig) {\n setConfig(userConfig);\n }\n registerComponents(registry);\n}\n"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@wcstack/raf",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.32.0",
|
|
4
4
|
"description": "Declarative requestAnimationFrame component for Web Components. Framework-agnostic frame-source primitive (tick/dt/suspended) via wc-bindable-protocol.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.esm.js",
|