@wcstack/idle 1.16.0 → 1.18.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 CHANGED
@@ -84,6 +84,59 @@ npm install @wcstack/idle
84
84
  | ----------- | ------ | ------- | ---- |
85
85
  | `threshold` | number | `60000` | `userState`が`"idle"`になるまでの最小アイドル時間(ms)。バリデーションなし——範囲外の値はブラウザ自身のrejectに委ねます。 |
86
86
 
87
+ ## `:state()` による CSS スタイリング
88
+
89
+ `<wcs-idle>` は 2 つの boolean 出力ステートを
90
+ [`ElementInternals` の `CustomStateSet`](https://developer.mozilla.org/ja/docs/Web/API/CustomStateSet)
91
+ に反映します。そのため `data-wcs` バインディングやクラスの手動トグルなしに、CSS の
92
+ `:state()` 疑似クラスで直接スタイリングできます。
93
+
94
+ | ステート | on になる条件 |
95
+ |----------|----------------|
96
+ | `active` | `wcs-idle:change` が `detail.userState === "active"` で発火(`"idle"` になったらクリア) |
97
+ | `error` | `wcs-idle:error` が非 `null` の detail で発火(`null` でクリア) |
98
+
99
+ `screenState` には派生 boolean getter が無いため(§4.2)、v1 では反映対象外です。
100
+
101
+ ```css
102
+ wcs-idle:state(active) ~ .presence-dot { background: green; }
103
+ wcs-idle:not(:state(active)) ~ .presence-dot { background: gray; }
104
+
105
+ form:has(wcs-idle:state(error)) .banner { display: block; }
106
+ ```
107
+
108
+ 属性やクラスと異なり `:state()` は要素の外部から書き込めないため、この出力ステートが
109
+ 入力と混同される心配がありません。
110
+
111
+ **対応ブラウザ**(新構文 `:state(x)`): Chrome/Edge 125+、Safari 17.4+、Firefox 126+。
112
+ 非対応の環境ではステートが一切 set されないだけです — `:state()` セレクタがマッチしなく
113
+ なりますが、`<wcs-idle>` 自体は通常どおり動作し続けます(graceful degradation・never-throw)。
114
+
115
+ **SSR:** `:state()` は HTML にシリアライズできないため、サーバーレンダリングされた
116
+ マークアップの初期ペイントにはこれらのステートは乗りません(`@wcstack/server` は無改変)。
117
+ ハイドレーション前の見た目を制御したい場合は、代わりに `wcs-idle:not(:defined)` と組み合わせてください。
118
+
119
+ ### デバッグ
120
+
121
+ カスタムステートは DevTools の Elements パネルには表示されず、`attachInternals()`
122
+ は同一要素に 2 回呼べないため、コンソールから直接覗く手段がありません。そのための
123
+ デバッグ専用の補助を 2 つ用意しています:
124
+
125
+ - `el.debugStates` — 現在 on になっているステート名の**スナップショット**配列
126
+ (例: `["active"]`)。`wc-bindable` の一部ではなく(バインド対象ではない)、
127
+ 形状も契約として保証されません — デバッグ用途にのみ使ってください。
128
+ - `debug-states` 属性(opt-in・既定 OFF)は、ステート変化を要素の
129
+ `data-wcs-state-active` / `data-wcs-state-error` 属性にミラーします。
130
+ Elements パネルを開いておけば、トグルのたびにハイライトされます:
131
+
132
+ ```html
133
+ <wcs-idle debug-states></wcs-idle>
134
+ ```
135
+
136
+ **CSS は `data-wcs-state-*` ではなく `:state()` に書いてください。** ミラーされた
137
+ 属性は、DevTools を開いた状態でステート変化を可視化するためだけのものであり、
138
+ スタイリング用の正式なフックではありません。
139
+
87
140
  ## 注意・制限
88
141
 
89
142
  - **connect時に自動startしません。** 上記「なぜ存在するか」を参照。
package/README.md CHANGED
@@ -86,6 +86,61 @@ npm install @wcstack/idle
86
86
  | ----------- | ------ | ------- | ------------ |
87
87
  | `threshold` | number | `60000` | Minimum idle time (ms) before `userState` becomes `"idle"`. Not validated — an out-of-range value is left to the browser's own rejection. |
88
88
 
89
+ ## CSS styling with `:state()`
90
+
91
+ `<wcs-idle>` reflects two boolean output states onto its
92
+ [`ElementInternals` `CustomStateSet`](https://developer.mozilla.org/en-US/docs/Web/API/CustomStateSet),
93
+ so you can style it directly from CSS with the `:state()` pseudo-class — no
94
+ `data-wcs` binding or extra class toggling required.
95
+
96
+ | State | On when |
97
+ |-------|---------|
98
+ | `active` | `wcs-idle:change` fires with `detail.userState === "active"` (cleared when it becomes `"idle"`) |
99
+ | `error` | `wcs-idle:error` fires with a non-`null` detail (cleared on `null`) |
100
+
101
+ `screenState` has no derived boolean getter (§4.2), so it is not reflected in v1.
102
+
103
+ ```css
104
+ wcs-idle:state(active) ~ .presence-dot { background: green; }
105
+ wcs-idle:not(:state(active)) ~ .presence-dot { background: gray; }
106
+
107
+ form:has(wcs-idle:state(error)) .banner { display: block; }
108
+ ```
109
+
110
+ Unlike attributes or classes, `:state()` cannot be written from outside the
111
+ element, so there is no risk of confusing this output state with an input.
112
+
113
+ **Browser support** (`:state(x)` syntax): Chrome/Edge 125+, Safari 17.4+,
114
+ Firefox 126+. In older browsers the states are simply never set — `:state()`
115
+ selectors never match, but `<wcs-idle>` itself keeps working normally
116
+ (graceful degradation, never-throw).
117
+
118
+ **SSR**: `:state()` cannot be serialized into HTML, so server-rendered markup
119
+ never carries these states on first paint (`@wcstack/server` is unaffected).
120
+ If you need to style the pre-hydration gap, pair your rule with
121
+ `wcs-idle:not(:defined)` instead.
122
+
123
+ ### Debugging
124
+
125
+ Custom states are invisible in DevTools' Elements panel and `attachInternals()`
126
+ cannot be called twice, so there is no console way to inspect them directly.
127
+ Two debug-only aids are provided for that:
128
+
129
+ - `el.debugStates` — a **snapshot** array of the currently-on state names
130
+ (e.g. `["active"]`). It is not part of `wc-bindable` (not a bind target)
131
+ and its shape is not a guaranteed contract — use it for debugging only.
132
+ - The `debug-states` attribute (opt-in, default off) mirrors state changes
133
+ onto `data-wcs-state-active` / `data-wcs-state-error` attributes on the
134
+ element, so the Elements panel highlights them as they toggle:
135
+
136
+ ```html
137
+ <wcs-idle debug-states></wcs-idle>
138
+ ```
139
+
140
+ **Write your CSS against `:state()`, not `data-wcs-state-*`.** The mirrored
141
+ attributes exist purely to make state changes visible while debugging with
142
+ DevTools open; they are not a supported styling hook.
143
+
89
144
  ## Notes & limitations
90
145
 
91
146
  - **Does not auto-start on connect.** See "Why this exists" above.
package/dist/index.d.ts CHANGED
@@ -131,7 +131,11 @@ declare class WcsIdle extends HTMLElement {
131
131
  static wcBindable: IWcBindable;
132
132
  private _core;
133
133
  private _connectedCallbackPromise;
134
+ private _internals;
134
135
  constructor();
136
+ get debugStates(): string[];
137
+ private _initInternals;
138
+ private _wireStates;
135
139
  /**
136
140
  * Minimum idle time (ms) before `userState` becomes `"idle"`. This value is
137
141
  * read only at `start()` time — there is no `attributeChangedCallback`
package/dist/index.esm.js CHANGED
@@ -255,9 +255,63 @@ class WcsIdle extends HTMLElement {
255
255
  };
256
256
  _core;
257
257
  _connectedCallbackPromise = Promise.resolve();
258
+ _internals = null;
258
259
  constructor() {
259
260
  super();
260
261
  this._core = new IdleCore(this);
262
+ this._internals = this._initInternals();
263
+ this._wireStates({
264
+ "wcs-idle:change": (d) => ({ active: d.userState === "active" }),
265
+ "wcs-idle:error": (d) => ({ error: d != null }),
266
+ });
267
+ }
268
+ // CSS state reflection (:state()) — debug-only snapshot getter. NOT part of
269
+ // wc-bindable (not a bind target); see README "CSS styling with :state()".
270
+ // MUST NOT return the live CustomStateSet (that would let callers write
271
+ // states from outside, defeating the point of :state() being read-only).
272
+ get debugStates() {
273
+ return this._internals ? [...this._internals.states] : [];
274
+ }
275
+ _initInternals() {
276
+ // never-throw (docs/custom-state-reflection-design.md §3.1/§3.4): attachInternals
277
+ // is absent in happy-dom / older environments, and pre-125 Chromium rejects
278
+ // non-dashed state names from states.add() (probed and discarded here).
279
+ // Either case silently disables reflection — the component still works,
280
+ // it just doesn't expose :state() selectors.
281
+ try {
282
+ if (typeof this.attachInternals !== "function")
283
+ return null;
284
+ const internals = this.attachInternals();
285
+ internals.states.add("wcs-probe");
286
+ internals.states.delete("wcs-probe");
287
+ return internals;
288
+ }
289
+ catch {
290
+ return null;
291
+ }
292
+ }
293
+ _wireStates(map) {
294
+ if (this._internals === null)
295
+ return;
296
+ const states = this._internals.states;
297
+ for (const [event, toStates] of Object.entries(map)) {
298
+ this.addEventListener(event, (e) => {
299
+ const debug = this.hasAttribute("debug-states");
300
+ for (const [name, on] of Object.entries(toStates(e.detail))) {
301
+ try {
302
+ if (on) {
303
+ states.add(name);
304
+ }
305
+ else {
306
+ states.delete(name);
307
+ }
308
+ }
309
+ catch { /* never-throw */ }
310
+ if (debug)
311
+ this.toggleAttribute(`data-wcs-state-${name}`, on);
312
+ }
313
+ });
314
+ }
261
315
  }
262
316
  // --- Attribute accessors ---
263
317
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"index.esm.js","sources":["../src/config.ts","../src/core/IdleCore.ts","../src/components/Idle.ts","../src/registerComponents.ts","../src/bootstrapIdle.ts"],"sourcesContent":["import { IConfig, IWritableConfig } from \"./types.js\";\n\ninterface IInternalConfig extends IConfig {\n tagNames: {\n idle: string;\n };\n}\n\nconst _config: IInternalConfig = {\n tagNames: {\n idle: \"wcs-idle\",\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\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 (partialConfig.tagNames) {\n Object.assign(_config.tagNames, partialConfig.tagNames);\n }\n frozenConfig = null;\n}\n","import { IdleScreenState, IdleUserState, IWcBindable } from \"../types.js\";\n\ninterface IdleDetectorLike extends EventTarget {\n userState: IdleUserState;\n screenState: IdleScreenState;\n start(options: { threshold: number; signal: AbortSignal }): Promise<void>;\n}\n\ninterface IdleDetectorCtor {\n new (): IdleDetectorLike;\n requestPermission(): Promise<\"granted\" | \"denied\">;\n}\n\nconst MIN_THRESHOLD = 60000;\n\n/**\n * Headless Idle Detection primitive. A thin, framework-agnostic wrapper around\n * `IdleDetector` exposed through the wc-bindable protocol.\n *\n * Reference implementation for batch2's \"gesture-gated permission\" archetype\n * (docs/idle-detection-tag-design.md). `requestPermission()` wraps the static,\n * user-gesture-gated `IdleDetector.requestPermission()` — this Core never\n * calls it automatically; the caller must invoke it from within a real\n * gesture handler.\n *\n * Deliberately does NOT track the 4-value permission state (prompt/granted/\n * denied/unsupported) itself: `navigator.permissions.query({name:\n * \"idle-detection\"})` exists, so compose with `<wcs-permission\n * name=\"idle-detection\">` for that instead (§0). This Core only exposes the\n * actual idle state (userState/screenState) plus the one-time\n * requestPermission()/start()/stop() actions.\n */\nexport class IdleCore extends EventTarget {\n static wcBindable: IWcBindable = {\n protocol: \"wc-bindable\",\n version: 1,\n properties: [\n { name: \"userState\", event: \"wcs-idle:change\", getter: (e: Event) => (e as CustomEvent).detail.userState },\n { name: \"screenState\", event: \"wcs-idle:change\", getter: (e: Event) => (e as CustomEvent).detail.screenState },\n {\n name: \"active\",\n event: \"wcs-idle:change\",\n getter: (e: Event) => (e as CustomEvent).detail.userState === \"active\",\n },\n // never-throw (§3.6): requestPermission()/start() failures land here\n // instead of rejecting/throwing. Mirrors every other bidirectional IO\n // node in this batch (fetch, share, screen-orientation).\n { name: \"error\", event: \"wcs-idle:error\" },\n ],\n // No `inputs`: the Core has no settable `threshold` state — `threshold` is a\n // per-call argument to `start(threshold)`, not a property/setter. The DOM-driven\n // `threshold` input surface belongs to the Shell (which declares it and backs it\n // with the `threshold` attribute), mirroring geolocation/intersection where the\n // Core declares no inputs and the Shell adds them.\n commands: [\n { name: \"requestPermission\", async: true },\n { name: \"start\", async: true },\n { name: \"stop\" },\n ],\n };\n\n private _target: EventTarget;\n private _userState: IdleUserState | null = null;\n private _screenState: IdleScreenState | null = null;\n private _error: any = null;\n private _detector: IdleDetectorLike | null = null;\n private _abortController: AbortController | null = null;\n\n // Generation guard (§3.4): bumped on dispose()/stop() and each start().\n private _gen = 0;\n\n // SSR (§3.8): never auto-starts on connect, so there is no probe to await —\n // readiness is always immediate (docs/idle-detection-tag-design.md §7).\n private _ready: Promise<void> = Promise.resolve();\n\n constructor(target?: EventTarget) {\n super();\n this._target = target ?? this;\n }\n\n get ready(): Promise<void> {\n return this._ready;\n }\n\n get userState(): IdleUserState | null {\n return this._userState;\n }\n\n get screenState(): IdleScreenState | null {\n return this._screenState;\n }\n\n get active(): boolean {\n return this._userState === \"active\";\n }\n\n get error(): any {\n return this._error;\n }\n\n // Lifecycle (§3.5). observe() is a synchronous no-op: unlike most IO nodes,\n // this Core deliberately does NOT auto-start on connect (§6) — permission\n // is gesture-gated, so attempting start() before it is granted is\n // guaranteed to fail.\n observe(): Promise<void> {\n return this._ready;\n }\n\n dispose(): void {\n this.stop();\n }\n\n private _api(): IdleDetectorCtor | undefined {\n const g = globalThis as any;\n return typeof g.IdleDetector === \"function\" ? g.IdleDetector : undefined;\n }\n\n private _setState(userState: IdleUserState, screenState: IdleScreenState): void {\n if (this._userState === userState && this._screenState === screenState) return;\n this._userState = userState;\n this._screenState = screenState;\n this._target.dispatchEvent(new CustomEvent(\"wcs-idle:change\", {\n detail: { userState, screenState },\n bubbles: true,\n }));\n }\n\n private _setError(error: any): void {\n if (this._error === error) return;\n this._error = error;\n this._target.dispatchEvent(new CustomEvent(\"wcs-idle:error\", {\n detail: error,\n bubbles: true,\n }));\n }\n\n /**\n * Wraps the static, user-gesture-gated `IdleDetector.requestPermission()`.\n * MUST be invoked from within a real user gesture handler by the caller —\n * this Core cannot manufacture one. never-throw: a gesture-context\n * rejection resolves to `\"denied\"` and lands in `error`. Gesture violation\n * and an actual \"denied\" outcome are not distinguished — both mean \"not\n * usable right now\" (§4.1).\n */\n async requestPermission(): Promise<\"granted\" | \"denied\"> {\n const Ctor = this._api();\n if (!Ctor) {\n this._setError({ message: \"IdleDetector is not supported in this browser\" });\n return \"denied\";\n }\n try {\n const result = await Ctor.requestPermission();\n // Symmetric with start()'s success path: any settled (non-throwing)\n // outcome — granted or a plain \"denied\" — supersedes a stale error from\n // an earlier attempt (e.g. a prior gesture-context rejection).\n this._setError(null);\n return result === \"granted\" ? \"granted\" : \"denied\";\n } catch (e) {\n this._setError({ error: e });\n return \"denied\";\n }\n }\n\n /**\n * Start an idle-detection session. `threshold` (ms) must be >= 60000 per\n * spec — not validated here (§3): an out-of-range value is left to the\n * browser's own TypeError, which never-throw absorbs into `error`.\n */\n async start(threshold: number = MIN_THRESHOLD): Promise<void> {\n this.stop(); // supersede any in-flight session (mirrors FetchCore's \"cancel then start\")\n\n const Ctor = this._api();\n if (!Ctor) {\n this._setError({ message: \"IdleDetector is not supported in this browser\" });\n return;\n }\n\n const ac = new AbortController();\n this._abortController = ac;\n const gen = ++this._gen;\n\n try {\n const detector = new Ctor();\n detector.addEventListener(\"change\", this._onChange);\n this._detector = detector;\n await detector.start({ threshold, signal: ac.signal });\n if (gen !== this._gen) return; // stale (stop()/dispose() ran during the await)\n this._setError(null);\n this._setState(detector.userState, detector.screenState);\n } catch (e: any) {\n // No separate AbortError check: stop()/dispose() bump `_gen` *before*\n // calling `ac.abort()` (see stop() below), so a stop()-triggered\n // AbortError always has a stale `gen` here and is already caught by\n // the check above. The signal is private and never exposed, so an\n // AbortError from any other source cannot occur.\n if (gen !== this._gen) return;\n // Tear down the failed session's listener/controller (mirrors stop()):\n // without this, the failed `_detector` stays wired to `_onChange` and a\n // later `change` on that same (never-truly-started) instance would\n // still write state, contradicting the error just recorded.\n this._detector?.removeEventListener(\"change\", this._onChange);\n this._detector = null;\n this._abortController = null;\n this._setError({ error: e });\n }\n }\n\n /** Stop the current session (if any) and detach its listener. Safe to call when not started. */\n stop(): void {\n this._gen++;\n this._abortController?.abort();\n this._abortController = null;\n if (this._detector) {\n this._detector.removeEventListener(\"change\", this._onChange);\n this._detector = null;\n }\n }\n\n private _onChange = (event: Event): void => {\n const detector = event.target as IdleDetectorLike;\n this._setState(detector.userState, detector.screenState);\n };\n}\n","import { IdleScreenState, IdleUserState, IWcBindable } from \"../types.js\";\nimport { IdleCore } from \"../core/IdleCore.js\";\n\n/**\n * `<wcs-idle>` — declarative Idle Detection API primitive.\n *\n * Does NOT auto-start on connect (docs/idle-detection-tag-design.md §6): the\n * permission gate sits in front of `start()`, so an unconditional\n * connectedCallback start would be guaranteed to fail before permission is\n * granted. Callers drive `requestPermission()` → `start()` explicitly, e.g.\n * from a click handler.\n *\n * Compose with `<wcs-permission name=\"idle-detection\">` for prompt/granted/\n * denied status — this Shell only exposes the actual idle state.\n */\nexport class WcsIdle extends HTMLElement {\n static hasConnectedCallbackPromise = true;\n\n static wcBindable: IWcBindable = {\n ...IdleCore.wcBindable,\n inputs: [\n { name: \"threshold\", attribute: \"threshold\" },\n ],\n // Core の commands をそのまま継承(単一情報源)。\n commands: IdleCore.wcBindable.commands,\n };\n\n private _core: IdleCore;\n private _connectedCallbackPromise: Promise<void> = Promise.resolve();\n\n constructor() {\n super();\n this._core = new IdleCore(this);\n }\n\n // --- Attribute accessors ---\n\n /**\n * Minimum idle time (ms) before `userState` becomes `\"idle\"`. This value is\n * read only at `start()` time — there is no `attributeChangedCallback`\n * (deliberately not declared in `observedAttributes`, mirroring\n * `<wcs-gyroscope>`'s `frequency`), so mutating the attribute/property on an\n * already-running session has no effect until the caller `stop()`s and\n * `start()`s again.\n */\n get threshold(): number {\n const attr = this.getAttribute(\"threshold\");\n // An absent, empty, or whitespace-only attribute all mean \"no value\n // supplied\" and must fall back to the default — without this check,\n // `Number(\"\")`/`Number(\" \")` coerce to `0` (finite), which would slip\n // past the `Number.isFinite` fallback below and silently return `0`\n // instead of the documented 60000ms default.\n if (attr === null || attr.trim() === \"\") return 60000;\n const n = Number(attr);\n return Number.isFinite(n) ? n : 60000;\n }\n\n set threshold(value: number) {\n this.setAttribute(\"threshold\", String(value));\n }\n\n // --- Core delegated getters ---\n\n get userState(): IdleUserState | null {\n return this._core.userState;\n }\n\n get screenState(): IdleScreenState | null {\n return this._core.screenState;\n }\n\n get active(): boolean {\n return this._core.active;\n }\n\n get error(): any {\n return this._core.error;\n }\n\n get connectedCallbackPromise(): Promise<void> {\n return this._connectedCallbackPromise;\n }\n\n // --- Commands (delegated to Core) ---\n\n requestPermission(): Promise<\"granted\" | \"denied\"> {\n return this._core.requestPermission();\n }\n\n start(threshold?: number): Promise<void> {\n return this._core.start(threshold ?? this.threshold);\n }\n\n stop(): void {\n this._core.stop();\n }\n\n // --- Lifecycle ---\n\n connectedCallback(): void {\n this.style.display = \"none\";\n // No auto-start (§6) — observe() is a synchronous no-op, kept only for\n // API uniformity with other IO nodes' lifecycle.\n this._connectedCallbackPromise = this._core.observe();\n }\n\n disconnectedCallback(): void {\n this._core.dispose();\n }\n}\n","import { WcsIdle } from \"./components/Idle.js\";\nimport { config } from \"./config.js\";\n\nexport function registerComponents(): void {\n if (!customElements.get(config.tagNames.idle)) {\n customElements.define(config.tagNames.idle, WcsIdle);\n }\n}\n","import { setConfig } from \"./config.js\";\nimport { registerComponents } from \"./registerComponents.js\";\nimport { IWritableConfig } from \"./types.js\";\n\nexport function bootstrapIdle(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/IdleCore.ts","../src/components/Idle.ts","../src/registerComponents.ts","../src/bootstrapIdle.ts"],"sourcesContent":["import { IConfig, IWritableConfig } from \"./types.js\";\n\ninterface IInternalConfig extends IConfig {\n tagNames: {\n idle: string;\n };\n}\n\nconst _config: IInternalConfig = {\n tagNames: {\n idle: \"wcs-idle\",\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\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 (partialConfig.tagNames) {\n Object.assign(_config.tagNames, partialConfig.tagNames);\n }\n frozenConfig = null;\n}\n","import { IdleScreenState, IdleUserState, IWcBindable } from \"../types.js\";\n\ninterface IdleDetectorLike extends EventTarget {\n userState: IdleUserState;\n screenState: IdleScreenState;\n start(options: { threshold: number; signal: AbortSignal }): Promise<void>;\n}\n\ninterface IdleDetectorCtor {\n new (): IdleDetectorLike;\n requestPermission(): Promise<\"granted\" | \"denied\">;\n}\n\nconst MIN_THRESHOLD = 60000;\n\n/**\n * Headless Idle Detection primitive. A thin, framework-agnostic wrapper around\n * `IdleDetector` exposed through the wc-bindable protocol.\n *\n * Reference implementation for batch2's \"gesture-gated permission\" archetype\n * (docs/idle-detection-tag-design.md). `requestPermission()` wraps the static,\n * user-gesture-gated `IdleDetector.requestPermission()` — this Core never\n * calls it automatically; the caller must invoke it from within a real\n * gesture handler.\n *\n * Deliberately does NOT track the 4-value permission state (prompt/granted/\n * denied/unsupported) itself: `navigator.permissions.query({name:\n * \"idle-detection\"})` exists, so compose with `<wcs-permission\n * name=\"idle-detection\">` for that instead (§0). This Core only exposes the\n * actual idle state (userState/screenState) plus the one-time\n * requestPermission()/start()/stop() actions.\n */\nexport class IdleCore extends EventTarget {\n static wcBindable: IWcBindable = {\n protocol: \"wc-bindable\",\n version: 1,\n properties: [\n { name: \"userState\", event: \"wcs-idle:change\", getter: (e: Event) => (e as CustomEvent).detail.userState },\n { name: \"screenState\", event: \"wcs-idle:change\", getter: (e: Event) => (e as CustomEvent).detail.screenState },\n {\n name: \"active\",\n event: \"wcs-idle:change\",\n getter: (e: Event) => (e as CustomEvent).detail.userState === \"active\",\n },\n // never-throw (§3.6): requestPermission()/start() failures land here\n // instead of rejecting/throwing. Mirrors every other bidirectional IO\n // node in this batch (fetch, share, screen-orientation).\n { name: \"error\", event: \"wcs-idle:error\" },\n ],\n // No `inputs`: the Core has no settable `threshold` state — `threshold` is a\n // per-call argument to `start(threshold)`, not a property/setter. The DOM-driven\n // `threshold` input surface belongs to the Shell (which declares it and backs it\n // with the `threshold` attribute), mirroring geolocation/intersection where the\n // Core declares no inputs and the Shell adds them.\n commands: [\n { name: \"requestPermission\", async: true },\n { name: \"start\", async: true },\n { name: \"stop\" },\n ],\n };\n\n private _target: EventTarget;\n private _userState: IdleUserState | null = null;\n private _screenState: IdleScreenState | null = null;\n private _error: any = null;\n private _detector: IdleDetectorLike | null = null;\n private _abortController: AbortController | null = null;\n\n // Generation guard (§3.4): bumped on dispose()/stop() and each start().\n private _gen = 0;\n\n // SSR (§3.8): never auto-starts on connect, so there is no probe to await —\n // readiness is always immediate (docs/idle-detection-tag-design.md §7).\n private _ready: Promise<void> = Promise.resolve();\n\n constructor(target?: EventTarget) {\n super();\n this._target = target ?? this;\n }\n\n get ready(): Promise<void> {\n return this._ready;\n }\n\n get userState(): IdleUserState | null {\n return this._userState;\n }\n\n get screenState(): IdleScreenState | null {\n return this._screenState;\n }\n\n get active(): boolean {\n return this._userState === \"active\";\n }\n\n get error(): any {\n return this._error;\n }\n\n // Lifecycle (§3.5). observe() is a synchronous no-op: unlike most IO nodes,\n // this Core deliberately does NOT auto-start on connect (§6) — permission\n // is gesture-gated, so attempting start() before it is granted is\n // guaranteed to fail.\n observe(): Promise<void> {\n return this._ready;\n }\n\n dispose(): void {\n this.stop();\n }\n\n private _api(): IdleDetectorCtor | undefined {\n const g = globalThis as any;\n return typeof g.IdleDetector === \"function\" ? g.IdleDetector : undefined;\n }\n\n private _setState(userState: IdleUserState, screenState: IdleScreenState): void {\n if (this._userState === userState && this._screenState === screenState) return;\n this._userState = userState;\n this._screenState = screenState;\n this._target.dispatchEvent(new CustomEvent(\"wcs-idle:change\", {\n detail: { userState, screenState },\n bubbles: true,\n }));\n }\n\n private _setError(error: any): void {\n if (this._error === error) return;\n this._error = error;\n this._target.dispatchEvent(new CustomEvent(\"wcs-idle:error\", {\n detail: error,\n bubbles: true,\n }));\n }\n\n /**\n * Wraps the static, user-gesture-gated `IdleDetector.requestPermission()`.\n * MUST be invoked from within a real user gesture handler by the caller —\n * this Core cannot manufacture one. never-throw: a gesture-context\n * rejection resolves to `\"denied\"` and lands in `error`. Gesture violation\n * and an actual \"denied\" outcome are not distinguished — both mean \"not\n * usable right now\" (§4.1).\n */\n async requestPermission(): Promise<\"granted\" | \"denied\"> {\n const Ctor = this._api();\n if (!Ctor) {\n this._setError({ message: \"IdleDetector is not supported in this browser\" });\n return \"denied\";\n }\n try {\n const result = await Ctor.requestPermission();\n // Symmetric with start()'s success path: any settled (non-throwing)\n // outcome — granted or a plain \"denied\" — supersedes a stale error from\n // an earlier attempt (e.g. a prior gesture-context rejection).\n this._setError(null);\n return result === \"granted\" ? \"granted\" : \"denied\";\n } catch (e) {\n this._setError({ error: e });\n return \"denied\";\n }\n }\n\n /**\n * Start an idle-detection session. `threshold` (ms) must be >= 60000 per\n * spec — not validated here (§3): an out-of-range value is left to the\n * browser's own TypeError, which never-throw absorbs into `error`.\n */\n async start(threshold: number = MIN_THRESHOLD): Promise<void> {\n this.stop(); // supersede any in-flight session (mirrors FetchCore's \"cancel then start\")\n\n const Ctor = this._api();\n if (!Ctor) {\n this._setError({ message: \"IdleDetector is not supported in this browser\" });\n return;\n }\n\n const ac = new AbortController();\n this._abortController = ac;\n const gen = ++this._gen;\n\n try {\n const detector = new Ctor();\n detector.addEventListener(\"change\", this._onChange);\n this._detector = detector;\n await detector.start({ threshold, signal: ac.signal });\n if (gen !== this._gen) return; // stale (stop()/dispose() ran during the await)\n this._setError(null);\n this._setState(detector.userState, detector.screenState);\n } catch (e: any) {\n // No separate AbortError check: stop()/dispose() bump `_gen` *before*\n // calling `ac.abort()` (see stop() below), so a stop()-triggered\n // AbortError always has a stale `gen` here and is already caught by\n // the check above. The signal is private and never exposed, so an\n // AbortError from any other source cannot occur.\n if (gen !== this._gen) return;\n // Tear down the failed session's listener/controller (mirrors stop()):\n // without this, the failed `_detector` stays wired to `_onChange` and a\n // later `change` on that same (never-truly-started) instance would\n // still write state, contradicting the error just recorded.\n this._detector?.removeEventListener(\"change\", this._onChange);\n this._detector = null;\n this._abortController = null;\n this._setError({ error: e });\n }\n }\n\n /** Stop the current session (if any) and detach its listener. Safe to call when not started. */\n stop(): void {\n this._gen++;\n this._abortController?.abort();\n this._abortController = null;\n if (this._detector) {\n this._detector.removeEventListener(\"change\", this._onChange);\n this._detector = null;\n }\n }\n\n private _onChange = (event: Event): void => {\n const detector = event.target as IdleDetectorLike;\n this._setState(detector.userState, detector.screenState);\n };\n}\n","import { IdleScreenState, IdleUserState, IWcBindable } from \"../types.js\";\nimport { IdleCore } from \"../core/IdleCore.js\";\n\n/**\n * `<wcs-idle>` — declarative Idle Detection API primitive.\n *\n * Does NOT auto-start on connect (docs/idle-detection-tag-design.md §6): the\n * permission gate sits in front of `start()`, so an unconditional\n * connectedCallback start would be guaranteed to fail before permission is\n * granted. Callers drive `requestPermission()` → `start()` explicitly, e.g.\n * from a click handler.\n *\n * Compose with `<wcs-permission name=\"idle-detection\">` for prompt/granted/\n * denied status — this Shell only exposes the actual idle state.\n */\nexport class WcsIdle extends HTMLElement {\n static hasConnectedCallbackPromise = true;\n\n static wcBindable: IWcBindable = {\n ...IdleCore.wcBindable,\n inputs: [\n { name: \"threshold\", attribute: \"threshold\" },\n ],\n // Core の commands をそのまま継承(単一情報源)。\n commands: IdleCore.wcBindable.commands,\n };\n\n private _core: IdleCore;\n private _connectedCallbackPromise: Promise<void> = Promise.resolve();\n private _internals: ElementInternals | null = null;\n\n constructor() {\n super();\n this._core = new IdleCore(this);\n this._internals = this._initInternals();\n this._wireStates({\n \"wcs-idle:change\": (d) => ({ active: d.userState === \"active\" }),\n \"wcs-idle:error\": (d) => ({ error: d != null }),\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 (docs/custom-state-reflection-design.md §3.1/§3.4): attachInternals\n // is absent 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 // --- Attribute accessors ---\n\n /**\n * Minimum idle time (ms) before `userState` becomes `\"idle\"`. This value is\n * read only at `start()` time — there is no `attributeChangedCallback`\n * (deliberately not declared in `observedAttributes`, mirroring\n * `<wcs-gyroscope>`'s `frequency`), so mutating the attribute/property on an\n * already-running session has no effect until the caller `stop()`s and\n * `start()`s again.\n */\n get threshold(): number {\n const attr = this.getAttribute(\"threshold\");\n // An absent, empty, or whitespace-only attribute all mean \"no value\n // supplied\" and must fall back to the default — without this check,\n // `Number(\"\")`/`Number(\" \")` coerce to `0` (finite), which would slip\n // past the `Number.isFinite` fallback below and silently return `0`\n // instead of the documented 60000ms default.\n if (attr === null || attr.trim() === \"\") return 60000;\n const n = Number(attr);\n return Number.isFinite(n) ? n : 60000;\n }\n\n set threshold(value: number) {\n this.setAttribute(\"threshold\", String(value));\n }\n\n // --- Core delegated getters ---\n\n get userState(): IdleUserState | null {\n return this._core.userState;\n }\n\n get screenState(): IdleScreenState | null {\n return this._core.screenState;\n }\n\n get active(): boolean {\n return this._core.active;\n }\n\n get error(): any {\n return this._core.error;\n }\n\n get connectedCallbackPromise(): Promise<void> {\n return this._connectedCallbackPromise;\n }\n\n // --- Commands (delegated to Core) ---\n\n requestPermission(): Promise<\"granted\" | \"denied\"> {\n return this._core.requestPermission();\n }\n\n start(threshold?: number): Promise<void> {\n return this._core.start(threshold ?? this.threshold);\n }\n\n stop(): void {\n this._core.stop();\n }\n\n // --- Lifecycle ---\n\n connectedCallback(): void {\n this.style.display = \"none\";\n // No auto-start (§6) — observe() is a synchronous no-op, kept only for\n // API uniformity with other IO nodes' lifecycle.\n this._connectedCallbackPromise = this._core.observe();\n }\n\n disconnectedCallback(): void {\n this._core.dispose();\n }\n}\n","import { WcsIdle } from \"./components/Idle.js\";\nimport { config } from \"./config.js\";\n\nexport function registerComponents(): void {\n if (!customElements.get(config.tagNames.idle)) {\n customElements.define(config.tagNames.idle, WcsIdle);\n }\n}\n","import { setConfig } from \"./config.js\";\nimport { registerComponents } from \"./registerComponents.js\";\nimport { IWritableConfig } from \"./types.js\";\n\nexport function bootstrapIdle(userConfig?: IWritableConfig): void {\n if (userConfig) {\n setConfig(userConfig);\n }\n registerComponents();\n}\n"],"names":[],"mappings":"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"}
@@ -1,2 +1,2 @@
1
- const e={tagNames:{idle:"wcs-idle"}};function t(e){if(null===e||"object"!=typeof e)return e;Object.freeze(e);for(const r of Object.keys(e))t(e[r]);return e}function r(e){if(null===e||"object"!=typeof e)return e;const t={};for(const s of Object.keys(e))t[s]=r(e[s]);return t}let s=null;const n=e;function i(){return s||(s=t(r(e))),s}class o extends EventTarget{static wcBindable={protocol:"wc-bindable",version:1,properties:[{name:"userState",event:"wcs-idle:change",getter:e=>e.detail.userState},{name:"screenState",event:"wcs-idle:change",getter:e=>e.detail.screenState},{name:"active",event:"wcs-idle:change",getter:e=>"active"===e.detail.userState},{name:"error",event:"wcs-idle:error"}],commands:[{name:"requestPermission",async:!0},{name:"start",async:!0},{name:"stop"}]};_target;_userState=null;_screenState=null;_error=null;_detector=null;_abortController=null;_gen=0;_ready=Promise.resolve();constructor(e){super(),this._target=e??this}get ready(){return this._ready}get userState(){return this._userState}get screenState(){return this._screenState}get active(){return"active"===this._userState}get error(){return this._error}observe(){return this._ready}dispose(){this.stop()}_api(){const e=globalThis;return"function"==typeof e.IdleDetector?e.IdleDetector:void 0}_setState(e,t){this._userState===e&&this._screenState===t||(this._userState=e,this._screenState=t,this._target.dispatchEvent(new CustomEvent("wcs-idle:change",{detail:{userState:e,screenState:t},bubbles:!0})))}_setError(e){this._error!==e&&(this._error=e,this._target.dispatchEvent(new CustomEvent("wcs-idle:error",{detail:e,bubbles:!0})))}async requestPermission(){const e=this._api();if(!e)return this._setError({message:"IdleDetector is not supported in this browser"}),"denied";try{const t=await e.requestPermission();return this._setError(null),"granted"===t?"granted":"denied"}catch(e){return this._setError({error:e}),"denied"}}async start(e=6e4){this.stop();const t=this._api();if(!t)return void this._setError({message:"IdleDetector is not supported in this browser"});const r=new AbortController;this._abortController=r;const s=++this._gen;try{const n=new t;if(n.addEventListener("change",this._onChange),this._detector=n,await n.start({threshold:e,signal:r.signal}),s!==this._gen)return;this._setError(null),this._setState(n.userState,n.screenState)}catch(e){if(s!==this._gen)return;this._detector?.removeEventListener("change",this._onChange),this._detector=null,this._abortController=null,this._setError({error:e})}}stop(){this._gen++,this._abortController?.abort(),this._abortController=null,this._detector&&(this._detector.removeEventListener("change",this._onChange),this._detector=null)}_onChange=e=>{const t=e.target;this._setState(t.userState,t.screenState)}}class a extends HTMLElement{static hasConnectedCallbackPromise=!0;static wcBindable={...o.wcBindable,inputs:[{name:"threshold",attribute:"threshold"}],commands:o.wcBindable.commands};_core;_connectedCallbackPromise=Promise.resolve();constructor(){super(),this._core=new o(this)}get threshold(){const e=this.getAttribute("threshold");if(null===e||""===e.trim())return 6e4;const t=Number(e);return Number.isFinite(t)?t:6e4}set threshold(e){this.setAttribute("threshold",String(e))}get userState(){return this._core.userState}get screenState(){return this._core.screenState}get active(){return this._core.active}get error(){return this._core.error}get connectedCallbackPromise(){return this._connectedCallbackPromise}requestPermission(){return this._core.requestPermission()}start(e){return this._core.start(e??this.threshold)}stop(){this._core.stop()}connectedCallback(){this.style.display="none",this._connectedCallbackPromise=this._core.observe()}disconnectedCallback(){this._core.dispose()}}function c(t){var r;t&&((r=t).tagNames&&Object.assign(e.tagNames,r.tagNames),s=null),customElements.get(n.tagNames.idle)||customElements.define(n.tagNames.idle,a)}export{o as IdleCore,a as WcsIdle,c as bootstrapIdle,i as getConfig};
1
+ const t={tagNames:{idle:"wcs-idle"}};function e(t){if(null===t||"object"!=typeof t)return t;Object.freeze(t);for(const r of Object.keys(t))e(t[r]);return t}function r(t){if(null===t||"object"!=typeof t)return t;const e={};for(const s of Object.keys(t))e[s]=r(t[s]);return e}let s=null;const n=t;function i(){return s||(s=e(r(t))),s}class a extends EventTarget{static wcBindable={protocol:"wc-bindable",version:1,properties:[{name:"userState",event:"wcs-idle:change",getter:t=>t.detail.userState},{name:"screenState",event:"wcs-idle:change",getter:t=>t.detail.screenState},{name:"active",event:"wcs-idle:change",getter:t=>"active"===t.detail.userState},{name:"error",event:"wcs-idle:error"}],commands:[{name:"requestPermission",async:!0},{name:"start",async:!0},{name:"stop"}]};_target;_userState=null;_screenState=null;_error=null;_detector=null;_abortController=null;_gen=0;_ready=Promise.resolve();constructor(t){super(),this._target=t??this}get ready(){return this._ready}get userState(){return this._userState}get screenState(){return this._screenState}get active(){return"active"===this._userState}get error(){return this._error}observe(){return this._ready}dispose(){this.stop()}_api(){const t=globalThis;return"function"==typeof t.IdleDetector?t.IdleDetector:void 0}_setState(t,e){this._userState===t&&this._screenState===e||(this._userState=t,this._screenState=e,this._target.dispatchEvent(new CustomEvent("wcs-idle:change",{detail:{userState:t,screenState:e},bubbles:!0})))}_setError(t){this._error!==t&&(this._error=t,this._target.dispatchEvent(new CustomEvent("wcs-idle:error",{detail:t,bubbles:!0})))}async requestPermission(){const t=this._api();if(!t)return this._setError({message:"IdleDetector is not supported in this browser"}),"denied";try{const e=await t.requestPermission();return this._setError(null),"granted"===e?"granted":"denied"}catch(t){return this._setError({error:t}),"denied"}}async start(t=6e4){this.stop();const e=this._api();if(!e)return void this._setError({message:"IdleDetector is not supported in this browser"});const r=new AbortController;this._abortController=r;const s=++this._gen;try{const n=new e;if(n.addEventListener("change",this._onChange),this._detector=n,await n.start({threshold:t,signal:r.signal}),s!==this._gen)return;this._setError(null),this._setState(n.userState,n.screenState)}catch(t){if(s!==this._gen)return;this._detector?.removeEventListener("change",this._onChange),this._detector=null,this._abortController=null,this._setError({error:t})}}stop(){this._gen++,this._abortController?.abort(),this._abortController=null,this._detector&&(this._detector.removeEventListener("change",this._onChange),this._detector=null)}_onChange=t=>{const e=t.target;this._setState(e.userState,e.screenState)}}class o extends HTMLElement{static hasConnectedCallbackPromise=!0;static wcBindable={...a.wcBindable,inputs:[{name:"threshold",attribute:"threshold"}],commands:a.wcBindable.commands};_core;_connectedCallbackPromise=Promise.resolve();_internals=null;constructor(){super(),this._core=new a(this),this._internals=this._initInternals(),this._wireStates({"wcs-idle:change":t=>({active:"active"===t.userState}),"wcs-idle:error":t=>({error:null!=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[r,s]of Object.entries(t))this.addEventListener(r,t=>{const r=this.hasAttribute("debug-states");for(const[n,i]of Object.entries(s(t.detail))){try{i?e.add(n):e.delete(n)}catch{}r&&this.toggleAttribute(`data-wcs-state-${n}`,i)}})}get threshold(){const t=this.getAttribute("threshold");if(null===t||""===t.trim())return 6e4;const e=Number(t);return Number.isFinite(e)?e:6e4}set threshold(t){this.setAttribute("threshold",String(t))}get userState(){return this._core.userState}get screenState(){return this._core.screenState}get active(){return this._core.active}get error(){return this._core.error}get connectedCallbackPromise(){return this._connectedCallbackPromise}requestPermission(){return this._core.requestPermission()}start(t){return this._core.start(t??this.threshold)}stop(){this._core.stop()}connectedCallback(){this.style.display="none",this._connectedCallbackPromise=this._core.observe()}disconnectedCallback(){this._core.dispose()}}function c(e){var r;e&&((r=e).tagNames&&Object.assign(t.tagNames,r.tagNames),s=null),customElements.get(n.tagNames.idle)||customElements.define(n.tagNames.idle,o)}export{a as IdleCore,o as WcsIdle,c as bootstrapIdle,i as getConfig};
2
2
  //# sourceMappingURL=index.esm.min.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.esm.min.js","sources":["../src/config.ts","../src/core/IdleCore.ts","../src/components/Idle.ts","../src/bootstrapIdle.ts","../src/registerComponents.ts"],"sourcesContent":["import { IConfig, IWritableConfig } from \"./types.js\";\n\ninterface IInternalConfig extends IConfig {\n tagNames: {\n idle: string;\n };\n}\n\nconst _config: IInternalConfig = {\n tagNames: {\n idle: \"wcs-idle\",\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\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 (partialConfig.tagNames) {\n Object.assign(_config.tagNames, partialConfig.tagNames);\n }\n frozenConfig = null;\n}\n","import { IdleScreenState, IdleUserState, IWcBindable } from \"../types.js\";\n\ninterface IdleDetectorLike extends EventTarget {\n userState: IdleUserState;\n screenState: IdleScreenState;\n start(options: { threshold: number; signal: AbortSignal }): Promise<void>;\n}\n\ninterface IdleDetectorCtor {\n new (): IdleDetectorLike;\n requestPermission(): Promise<\"granted\" | \"denied\">;\n}\n\nconst MIN_THRESHOLD = 60000;\n\n/**\n * Headless Idle Detection primitive. A thin, framework-agnostic wrapper around\n * `IdleDetector` exposed through the wc-bindable protocol.\n *\n * Reference implementation for batch2's \"gesture-gated permission\" archetype\n * (docs/idle-detection-tag-design.md). `requestPermission()` wraps the static,\n * user-gesture-gated `IdleDetector.requestPermission()` — this Core never\n * calls it automatically; the caller must invoke it from within a real\n * gesture handler.\n *\n * Deliberately does NOT track the 4-value permission state (prompt/granted/\n * denied/unsupported) itself: `navigator.permissions.query({name:\n * \"idle-detection\"})` exists, so compose with `<wcs-permission\n * name=\"idle-detection\">` for that instead (§0). This Core only exposes the\n * actual idle state (userState/screenState) plus the one-time\n * requestPermission()/start()/stop() actions.\n */\nexport class IdleCore extends EventTarget {\n static wcBindable: IWcBindable = {\n protocol: \"wc-bindable\",\n version: 1,\n properties: [\n { name: \"userState\", event: \"wcs-idle:change\", getter: (e: Event) => (e as CustomEvent).detail.userState },\n { name: \"screenState\", event: \"wcs-idle:change\", getter: (e: Event) => (e as CustomEvent).detail.screenState },\n {\n name: \"active\",\n event: \"wcs-idle:change\",\n getter: (e: Event) => (e as CustomEvent).detail.userState === \"active\",\n },\n // never-throw (§3.6): requestPermission()/start() failures land here\n // instead of rejecting/throwing. Mirrors every other bidirectional IO\n // node in this batch (fetch, share, screen-orientation).\n { name: \"error\", event: \"wcs-idle:error\" },\n ],\n // No `inputs`: the Core has no settable `threshold` state — `threshold` is a\n // per-call argument to `start(threshold)`, not a property/setter. The DOM-driven\n // `threshold` input surface belongs to the Shell (which declares it and backs it\n // with the `threshold` attribute), mirroring geolocation/intersection where the\n // Core declares no inputs and the Shell adds them.\n commands: [\n { name: \"requestPermission\", async: true },\n { name: \"start\", async: true },\n { name: \"stop\" },\n ],\n };\n\n private _target: EventTarget;\n private _userState: IdleUserState | null = null;\n private _screenState: IdleScreenState | null = null;\n private _error: any = null;\n private _detector: IdleDetectorLike | null = null;\n private _abortController: AbortController | null = null;\n\n // Generation guard (§3.4): bumped on dispose()/stop() and each start().\n private _gen = 0;\n\n // SSR (§3.8): never auto-starts on connect, so there is no probe to await —\n // readiness is always immediate (docs/idle-detection-tag-design.md §7).\n private _ready: Promise<void> = Promise.resolve();\n\n constructor(target?: EventTarget) {\n super();\n this._target = target ?? this;\n }\n\n get ready(): Promise<void> {\n return this._ready;\n }\n\n get userState(): IdleUserState | null {\n return this._userState;\n }\n\n get screenState(): IdleScreenState | null {\n return this._screenState;\n }\n\n get active(): boolean {\n return this._userState === \"active\";\n }\n\n get error(): any {\n return this._error;\n }\n\n // Lifecycle (§3.5). observe() is a synchronous no-op: unlike most IO nodes,\n // this Core deliberately does NOT auto-start on connect (§6) — permission\n // is gesture-gated, so attempting start() before it is granted is\n // guaranteed to fail.\n observe(): Promise<void> {\n return this._ready;\n }\n\n dispose(): void {\n this.stop();\n }\n\n private _api(): IdleDetectorCtor | undefined {\n const g = globalThis as any;\n return typeof g.IdleDetector === \"function\" ? g.IdleDetector : undefined;\n }\n\n private _setState(userState: IdleUserState, screenState: IdleScreenState): void {\n if (this._userState === userState && this._screenState === screenState) return;\n this._userState = userState;\n this._screenState = screenState;\n this._target.dispatchEvent(new CustomEvent(\"wcs-idle:change\", {\n detail: { userState, screenState },\n bubbles: true,\n }));\n }\n\n private _setError(error: any): void {\n if (this._error === error) return;\n this._error = error;\n this._target.dispatchEvent(new CustomEvent(\"wcs-idle:error\", {\n detail: error,\n bubbles: true,\n }));\n }\n\n /**\n * Wraps the static, user-gesture-gated `IdleDetector.requestPermission()`.\n * MUST be invoked from within a real user gesture handler by the caller —\n * this Core cannot manufacture one. never-throw: a gesture-context\n * rejection resolves to `\"denied\"` and lands in `error`. Gesture violation\n * and an actual \"denied\" outcome are not distinguished — both mean \"not\n * usable right now\" (§4.1).\n */\n async requestPermission(): Promise<\"granted\" | \"denied\"> {\n const Ctor = this._api();\n if (!Ctor) {\n this._setError({ message: \"IdleDetector is not supported in this browser\" });\n return \"denied\";\n }\n try {\n const result = await Ctor.requestPermission();\n // Symmetric with start()'s success path: any settled (non-throwing)\n // outcome — granted or a plain \"denied\" — supersedes a stale error from\n // an earlier attempt (e.g. a prior gesture-context rejection).\n this._setError(null);\n return result === \"granted\" ? \"granted\" : \"denied\";\n } catch (e) {\n this._setError({ error: e });\n return \"denied\";\n }\n }\n\n /**\n * Start an idle-detection session. `threshold` (ms) must be >= 60000 per\n * spec — not validated here (§3): an out-of-range value is left to the\n * browser's own TypeError, which never-throw absorbs into `error`.\n */\n async start(threshold: number = MIN_THRESHOLD): Promise<void> {\n this.stop(); // supersede any in-flight session (mirrors FetchCore's \"cancel then start\")\n\n const Ctor = this._api();\n if (!Ctor) {\n this._setError({ message: \"IdleDetector is not supported in this browser\" });\n return;\n }\n\n const ac = new AbortController();\n this._abortController = ac;\n const gen = ++this._gen;\n\n try {\n const detector = new Ctor();\n detector.addEventListener(\"change\", this._onChange);\n this._detector = detector;\n await detector.start({ threshold, signal: ac.signal });\n if (gen !== this._gen) return; // stale (stop()/dispose() ran during the await)\n this._setError(null);\n this._setState(detector.userState, detector.screenState);\n } catch (e: any) {\n // No separate AbortError check: stop()/dispose() bump `_gen` *before*\n // calling `ac.abort()` (see stop() below), so a stop()-triggered\n // AbortError always has a stale `gen` here and is already caught by\n // the check above. The signal is private and never exposed, so an\n // AbortError from any other source cannot occur.\n if (gen !== this._gen) return;\n // Tear down the failed session's listener/controller (mirrors stop()):\n // without this, the failed `_detector` stays wired to `_onChange` and a\n // later `change` on that same (never-truly-started) instance would\n // still write state, contradicting the error just recorded.\n this._detector?.removeEventListener(\"change\", this._onChange);\n this._detector = null;\n this._abortController = null;\n this._setError({ error: e });\n }\n }\n\n /** Stop the current session (if any) and detach its listener. Safe to call when not started. */\n stop(): void {\n this._gen++;\n this._abortController?.abort();\n this._abortController = null;\n if (this._detector) {\n this._detector.removeEventListener(\"change\", this._onChange);\n this._detector = null;\n }\n }\n\n private _onChange = (event: Event): void => {\n const detector = event.target as IdleDetectorLike;\n this._setState(detector.userState, detector.screenState);\n };\n}\n","import { IdleScreenState, IdleUserState, IWcBindable } from \"../types.js\";\nimport { IdleCore } from \"../core/IdleCore.js\";\n\n/**\n * `<wcs-idle>` — declarative Idle Detection API primitive.\n *\n * Does NOT auto-start on connect (docs/idle-detection-tag-design.md §6): the\n * permission gate sits in front of `start()`, so an unconditional\n * connectedCallback start would be guaranteed to fail before permission is\n * granted. Callers drive `requestPermission()` → `start()` explicitly, e.g.\n * from a click handler.\n *\n * Compose with `<wcs-permission name=\"idle-detection\">` for prompt/granted/\n * denied status — this Shell only exposes the actual idle state.\n */\nexport class WcsIdle extends HTMLElement {\n static hasConnectedCallbackPromise = true;\n\n static wcBindable: IWcBindable = {\n ...IdleCore.wcBindable,\n inputs: [\n { name: \"threshold\", attribute: \"threshold\" },\n ],\n // Core の commands をそのまま継承(単一情報源)。\n commands: IdleCore.wcBindable.commands,\n };\n\n private _core: IdleCore;\n private _connectedCallbackPromise: Promise<void> = Promise.resolve();\n\n constructor() {\n super();\n this._core = new IdleCore(this);\n }\n\n // --- Attribute accessors ---\n\n /**\n * Minimum idle time (ms) before `userState` becomes `\"idle\"`. This value is\n * read only at `start()` time — there is no `attributeChangedCallback`\n * (deliberately not declared in `observedAttributes`, mirroring\n * `<wcs-gyroscope>`'s `frequency`), so mutating the attribute/property on an\n * already-running session has no effect until the caller `stop()`s and\n * `start()`s again.\n */\n get threshold(): number {\n const attr = this.getAttribute(\"threshold\");\n // An absent, empty, or whitespace-only attribute all mean \"no value\n // supplied\" and must fall back to the default — without this check,\n // `Number(\"\")`/`Number(\" \")` coerce to `0` (finite), which would slip\n // past the `Number.isFinite` fallback below and silently return `0`\n // instead of the documented 60000ms default.\n if (attr === null || attr.trim() === \"\") return 60000;\n const n = Number(attr);\n return Number.isFinite(n) ? n : 60000;\n }\n\n set threshold(value: number) {\n this.setAttribute(\"threshold\", String(value));\n }\n\n // --- Core delegated getters ---\n\n get userState(): IdleUserState | null {\n return this._core.userState;\n }\n\n get screenState(): IdleScreenState | null {\n return this._core.screenState;\n }\n\n get active(): boolean {\n return this._core.active;\n }\n\n get error(): any {\n return this._core.error;\n }\n\n get connectedCallbackPromise(): Promise<void> {\n return this._connectedCallbackPromise;\n }\n\n // --- Commands (delegated to Core) ---\n\n requestPermission(): Promise<\"granted\" | \"denied\"> {\n return this._core.requestPermission();\n }\n\n start(threshold?: number): Promise<void> {\n return this._core.start(threshold ?? this.threshold);\n }\n\n stop(): void {\n this._core.stop();\n }\n\n // --- Lifecycle ---\n\n connectedCallback(): void {\n this.style.display = \"none\";\n // No auto-start (§6) — observe() is a synchronous no-op, kept only for\n // API uniformity with other IO nodes' lifecycle.\n this._connectedCallbackPromise = this._core.observe();\n }\n\n disconnectedCallback(): void {\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 bootstrapIdle(userConfig?: IWritableConfig): void {\n if (userConfig) {\n setConfig(userConfig);\n }\n registerComponents();\n}\n","import { WcsIdle } from \"./components/Idle.js\";\nimport { config } from \"./config.js\";\n\nexport function registerComponents(): void {\n if (!customElements.get(config.tagNames.idle)) {\n customElements.define(config.tagNames.idle, WcsIdle);\n }\n}\n"],"names":["_config","tagNames","idle","deepFreeze","obj","Object","freeze","key","keys","deepClone","clone","frozenConfig","config","getConfig","IdleCore","EventTarget","static","protocol","version","properties","name","event","getter","e","detail","userState","screenState","commands","async","_target","_userState","_screenState","_error","_detector","_abortController","_gen","_ready","Promise","resolve","constructor","target","super","this","ready","active","error","observe","dispose","stop","_api","g","globalThis","IdleDetector","undefined","_setState","dispatchEvent","CustomEvent","bubbles","_setError","requestPermission","Ctor","message","result","start","threshold","ac","AbortController","gen","detector","addEventListener","_onChange","signal","removeEventListener","abort","WcsIdle","HTMLElement","wcBindable","inputs","attribute","_core","_connectedCallbackPromise","attr","getAttribute","trim","n","Number","isFinite","value","setAttribute","String","connectedCallbackPromise","connectedCallback","style","display","disconnectedCallback","bootstrapIdle","userConfig","partialConfig","assign","customElements","get","define"],"mappings":"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"}
1
+ {"version":3,"file":"index.esm.min.js","sources":["../src/config.ts","../src/core/IdleCore.ts","../src/components/Idle.ts","../src/bootstrapIdle.ts","../src/registerComponents.ts"],"sourcesContent":["import { IConfig, IWritableConfig } from \"./types.js\";\n\ninterface IInternalConfig extends IConfig {\n tagNames: {\n idle: string;\n };\n}\n\nconst _config: IInternalConfig = {\n tagNames: {\n idle: \"wcs-idle\",\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\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 (partialConfig.tagNames) {\n Object.assign(_config.tagNames, partialConfig.tagNames);\n }\n frozenConfig = null;\n}\n","import { IdleScreenState, IdleUserState, IWcBindable } from \"../types.js\";\n\ninterface IdleDetectorLike extends EventTarget {\n userState: IdleUserState;\n screenState: IdleScreenState;\n start(options: { threshold: number; signal: AbortSignal }): Promise<void>;\n}\n\ninterface IdleDetectorCtor {\n new (): IdleDetectorLike;\n requestPermission(): Promise<\"granted\" | \"denied\">;\n}\n\nconst MIN_THRESHOLD = 60000;\n\n/**\n * Headless Idle Detection primitive. A thin, framework-agnostic wrapper around\n * `IdleDetector` exposed through the wc-bindable protocol.\n *\n * Reference implementation for batch2's \"gesture-gated permission\" archetype\n * (docs/idle-detection-tag-design.md). `requestPermission()` wraps the static,\n * user-gesture-gated `IdleDetector.requestPermission()` — this Core never\n * calls it automatically; the caller must invoke it from within a real\n * gesture handler.\n *\n * Deliberately does NOT track the 4-value permission state (prompt/granted/\n * denied/unsupported) itself: `navigator.permissions.query({name:\n * \"idle-detection\"})` exists, so compose with `<wcs-permission\n * name=\"idle-detection\">` for that instead (§0). This Core only exposes the\n * actual idle state (userState/screenState) plus the one-time\n * requestPermission()/start()/stop() actions.\n */\nexport class IdleCore extends EventTarget {\n static wcBindable: IWcBindable = {\n protocol: \"wc-bindable\",\n version: 1,\n properties: [\n { name: \"userState\", event: \"wcs-idle:change\", getter: (e: Event) => (e as CustomEvent).detail.userState },\n { name: \"screenState\", event: \"wcs-idle:change\", getter: (e: Event) => (e as CustomEvent).detail.screenState },\n {\n name: \"active\",\n event: \"wcs-idle:change\",\n getter: (e: Event) => (e as CustomEvent).detail.userState === \"active\",\n },\n // never-throw (§3.6): requestPermission()/start() failures land here\n // instead of rejecting/throwing. Mirrors every other bidirectional IO\n // node in this batch (fetch, share, screen-orientation).\n { name: \"error\", event: \"wcs-idle:error\" },\n ],\n // No `inputs`: the Core has no settable `threshold` state — `threshold` is a\n // per-call argument to `start(threshold)`, not a property/setter. The DOM-driven\n // `threshold` input surface belongs to the Shell (which declares it and backs it\n // with the `threshold` attribute), mirroring geolocation/intersection where the\n // Core declares no inputs and the Shell adds them.\n commands: [\n { name: \"requestPermission\", async: true },\n { name: \"start\", async: true },\n { name: \"stop\" },\n ],\n };\n\n private _target: EventTarget;\n private _userState: IdleUserState | null = null;\n private _screenState: IdleScreenState | null = null;\n private _error: any = null;\n private _detector: IdleDetectorLike | null = null;\n private _abortController: AbortController | null = null;\n\n // Generation guard (§3.4): bumped on dispose()/stop() and each start().\n private _gen = 0;\n\n // SSR (§3.8): never auto-starts on connect, so there is no probe to await —\n // readiness is always immediate (docs/idle-detection-tag-design.md §7).\n private _ready: Promise<void> = Promise.resolve();\n\n constructor(target?: EventTarget) {\n super();\n this._target = target ?? this;\n }\n\n get ready(): Promise<void> {\n return this._ready;\n }\n\n get userState(): IdleUserState | null {\n return this._userState;\n }\n\n get screenState(): IdleScreenState | null {\n return this._screenState;\n }\n\n get active(): boolean {\n return this._userState === \"active\";\n }\n\n get error(): any {\n return this._error;\n }\n\n // Lifecycle (§3.5). observe() is a synchronous no-op: unlike most IO nodes,\n // this Core deliberately does NOT auto-start on connect (§6) — permission\n // is gesture-gated, so attempting start() before it is granted is\n // guaranteed to fail.\n observe(): Promise<void> {\n return this._ready;\n }\n\n dispose(): void {\n this.stop();\n }\n\n private _api(): IdleDetectorCtor | undefined {\n const g = globalThis as any;\n return typeof g.IdleDetector === \"function\" ? g.IdleDetector : undefined;\n }\n\n private _setState(userState: IdleUserState, screenState: IdleScreenState): void {\n if (this._userState === userState && this._screenState === screenState) return;\n this._userState = userState;\n this._screenState = screenState;\n this._target.dispatchEvent(new CustomEvent(\"wcs-idle:change\", {\n detail: { userState, screenState },\n bubbles: true,\n }));\n }\n\n private _setError(error: any): void {\n if (this._error === error) return;\n this._error = error;\n this._target.dispatchEvent(new CustomEvent(\"wcs-idle:error\", {\n detail: error,\n bubbles: true,\n }));\n }\n\n /**\n * Wraps the static, user-gesture-gated `IdleDetector.requestPermission()`.\n * MUST be invoked from within a real user gesture handler by the caller —\n * this Core cannot manufacture one. never-throw: a gesture-context\n * rejection resolves to `\"denied\"` and lands in `error`. Gesture violation\n * and an actual \"denied\" outcome are not distinguished — both mean \"not\n * usable right now\" (§4.1).\n */\n async requestPermission(): Promise<\"granted\" | \"denied\"> {\n const Ctor = this._api();\n if (!Ctor) {\n this._setError({ message: \"IdleDetector is not supported in this browser\" });\n return \"denied\";\n }\n try {\n const result = await Ctor.requestPermission();\n // Symmetric with start()'s success path: any settled (non-throwing)\n // outcome — granted or a plain \"denied\" — supersedes a stale error from\n // an earlier attempt (e.g. a prior gesture-context rejection).\n this._setError(null);\n return result === \"granted\" ? \"granted\" : \"denied\";\n } catch (e) {\n this._setError({ error: e });\n return \"denied\";\n }\n }\n\n /**\n * Start an idle-detection session. `threshold` (ms) must be >= 60000 per\n * spec — not validated here (§3): an out-of-range value is left to the\n * browser's own TypeError, which never-throw absorbs into `error`.\n */\n async start(threshold: number = MIN_THRESHOLD): Promise<void> {\n this.stop(); // supersede any in-flight session (mirrors FetchCore's \"cancel then start\")\n\n const Ctor = this._api();\n if (!Ctor) {\n this._setError({ message: \"IdleDetector is not supported in this browser\" });\n return;\n }\n\n const ac = new AbortController();\n this._abortController = ac;\n const gen = ++this._gen;\n\n try {\n const detector = new Ctor();\n detector.addEventListener(\"change\", this._onChange);\n this._detector = detector;\n await detector.start({ threshold, signal: ac.signal });\n if (gen !== this._gen) return; // stale (stop()/dispose() ran during the await)\n this._setError(null);\n this._setState(detector.userState, detector.screenState);\n } catch (e: any) {\n // No separate AbortError check: stop()/dispose() bump `_gen` *before*\n // calling `ac.abort()` (see stop() below), so a stop()-triggered\n // AbortError always has a stale `gen` here and is already caught by\n // the check above. The signal is private and never exposed, so an\n // AbortError from any other source cannot occur.\n if (gen !== this._gen) return;\n // Tear down the failed session's listener/controller (mirrors stop()):\n // without this, the failed `_detector` stays wired to `_onChange` and a\n // later `change` on that same (never-truly-started) instance would\n // still write state, contradicting the error just recorded.\n this._detector?.removeEventListener(\"change\", this._onChange);\n this._detector = null;\n this._abortController = null;\n this._setError({ error: e });\n }\n }\n\n /** Stop the current session (if any) and detach its listener. Safe to call when not started. */\n stop(): void {\n this._gen++;\n this._abortController?.abort();\n this._abortController = null;\n if (this._detector) {\n this._detector.removeEventListener(\"change\", this._onChange);\n this._detector = null;\n }\n }\n\n private _onChange = (event: Event): void => {\n const detector = event.target as IdleDetectorLike;\n this._setState(detector.userState, detector.screenState);\n };\n}\n","import { IdleScreenState, IdleUserState, IWcBindable } from \"../types.js\";\nimport { IdleCore } from \"../core/IdleCore.js\";\n\n/**\n * `<wcs-idle>` — declarative Idle Detection API primitive.\n *\n * Does NOT auto-start on connect (docs/idle-detection-tag-design.md §6): the\n * permission gate sits in front of `start()`, so an unconditional\n * connectedCallback start would be guaranteed to fail before permission is\n * granted. Callers drive `requestPermission()` → `start()` explicitly, e.g.\n * from a click handler.\n *\n * Compose with `<wcs-permission name=\"idle-detection\">` for prompt/granted/\n * denied status — this Shell only exposes the actual idle state.\n */\nexport class WcsIdle extends HTMLElement {\n static hasConnectedCallbackPromise = true;\n\n static wcBindable: IWcBindable = {\n ...IdleCore.wcBindable,\n inputs: [\n { name: \"threshold\", attribute: \"threshold\" },\n ],\n // Core の commands をそのまま継承(単一情報源)。\n commands: IdleCore.wcBindable.commands,\n };\n\n private _core: IdleCore;\n private _connectedCallbackPromise: Promise<void> = Promise.resolve();\n private _internals: ElementInternals | null = null;\n\n constructor() {\n super();\n this._core = new IdleCore(this);\n this._internals = this._initInternals();\n this._wireStates({\n \"wcs-idle:change\": (d) => ({ active: d.userState === \"active\" }),\n \"wcs-idle:error\": (d) => ({ error: d != null }),\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 (docs/custom-state-reflection-design.md §3.1/§3.4): attachInternals\n // is absent 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 // --- Attribute accessors ---\n\n /**\n * Minimum idle time (ms) before `userState` becomes `\"idle\"`. This value is\n * read only at `start()` time — there is no `attributeChangedCallback`\n * (deliberately not declared in `observedAttributes`, mirroring\n * `<wcs-gyroscope>`'s `frequency`), so mutating the attribute/property on an\n * already-running session has no effect until the caller `stop()`s and\n * `start()`s again.\n */\n get threshold(): number {\n const attr = this.getAttribute(\"threshold\");\n // An absent, empty, or whitespace-only attribute all mean \"no value\n // supplied\" and must fall back to the default — without this check,\n // `Number(\"\")`/`Number(\" \")` coerce to `0` (finite), which would slip\n // past the `Number.isFinite` fallback below and silently return `0`\n // instead of the documented 60000ms default.\n if (attr === null || attr.trim() === \"\") return 60000;\n const n = Number(attr);\n return Number.isFinite(n) ? n : 60000;\n }\n\n set threshold(value: number) {\n this.setAttribute(\"threshold\", String(value));\n }\n\n // --- Core delegated getters ---\n\n get userState(): IdleUserState | null {\n return this._core.userState;\n }\n\n get screenState(): IdleScreenState | null {\n return this._core.screenState;\n }\n\n get active(): boolean {\n return this._core.active;\n }\n\n get error(): any {\n return this._core.error;\n }\n\n get connectedCallbackPromise(): Promise<void> {\n return this._connectedCallbackPromise;\n }\n\n // --- Commands (delegated to Core) ---\n\n requestPermission(): Promise<\"granted\" | \"denied\"> {\n return this._core.requestPermission();\n }\n\n start(threshold?: number): Promise<void> {\n return this._core.start(threshold ?? this.threshold);\n }\n\n stop(): void {\n this._core.stop();\n }\n\n // --- Lifecycle ---\n\n connectedCallback(): void {\n this.style.display = \"none\";\n // No auto-start (§6) — observe() is a synchronous no-op, kept only for\n // API uniformity with other IO nodes' lifecycle.\n this._connectedCallbackPromise = this._core.observe();\n }\n\n disconnectedCallback(): void {\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 bootstrapIdle(userConfig?: IWritableConfig): void {\n if (userConfig) {\n setConfig(userConfig);\n }\n registerComponents();\n}\n","import { WcsIdle } from \"./components/Idle.js\";\nimport { config } from \"./config.js\";\n\nexport function registerComponents(): void {\n if (!customElements.get(config.tagNames.idle)) {\n customElements.define(config.tagNames.idle, WcsIdle);\n }\n}\n"],"names":["_config","tagNames","idle","deepFreeze","obj","Object","freeze","key","keys","deepClone","clone","frozenConfig","config","getConfig","IdleCore","EventTarget","static","protocol","version","properties","name","event","getter","e","detail","userState","screenState","commands","async","_target","_userState","_screenState","_error","_detector","_abortController","_gen","_ready","Promise","resolve","constructor","target","super","this","ready","active","error","observe","dispose","stop","_api","g","globalThis","IdleDetector","undefined","_setState","dispatchEvent","CustomEvent","bubbles","_setError","requestPermission","Ctor","message","result","start","threshold","ac","AbortController","gen","detector","addEventListener","_onChange","signal","removeEventListener","abort","WcsIdle","HTMLElement","wcBindable","inputs","attribute","_core","_connectedCallbackPromise","_internals","_initInternals","_wireStates","d","debugStates","states","attachInternals","internals","add","delete","map","toStates","entries","debug","hasAttribute","on","toggleAttribute","attr","getAttribute","trim","n","Number","isFinite","value","setAttribute","String","connectedCallbackPromise","connectedCallback","style","display","disconnectedCallback","bootstrapIdle","userConfig","partialConfig","assign","customElements","get","define"],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@wcstack/idle",
3
- "version": "1.16.0",
3
+ "version": "1.18.0",
4
4
  "description": "Declarative Idle Detection component for Web Components. Framework-agnostic IdleDetector wrapper via wc-bindable-protocol.",
5
5
  "type": "module",
6
6
  "main": "./dist/index.esm.js",