@wcstack/accelerometer 1.16.0 → 1.17.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
@@ -117,6 +117,58 @@ npm install @wcstack/accelerometer
117
117
  - **生の`new Accelerometer(...)`は唯一のガード付き構築ヘルパー以外では呼ばない。** 権限拒否・Permissions-Policyブロックは同期的に例外を投げます。
118
118
  - 権限状態(`granted`/`denied`/`prompt`)は意図的にこのノードでは重複実装していません — `<wcs-permission name="accelerometer">`と合成してください。
119
119
 
120
+ ## `:state()` による CSS スタイリング
121
+
122
+ `<wcs-accelerometer>` は1つの boolean 出力ステートを
123
+ [`ElementInternals` の `CustomStateSet`](https://developer.mozilla.org/ja/docs/Web/API/CustomStateSet)
124
+ に反映します。そのため `data-wcs` バインディングやクラスの手動トグルなしに、CSS の
125
+ `:state()` 疑似クラスで直接スタイリングできます。`x`/`y`/`z`(連続的なセンサー読み取り値)
126
+ は意図的に反映**しません** — `docs/custom-state-reflection-design.md` §3.2 参照。
127
+
128
+ | ステート | on になる条件 |
129
+ |----------|----------------|
130
+ | `error` | `wcs-accelerometer:error` が非 `null` の detail で発火(`null` でクリア) |
131
+
132
+ ```css
133
+ wcs-accelerometer:state(error) ~ .fallback { display: block; }
134
+ ```
135
+
136
+ `error` は sticky です(上記「注意・制限」参照): 一度 on になると、後続の
137
+ `wcs-accelerometer:error` が `null` の detail で発火するまで on のままです —
138
+ その後の `start()` 成功や `reading` 受信では自動クリアされません。
139
+
140
+ 属性やクラスと異なり `:state()` は要素の外部から書き込めないため、この出力ステートが
141
+ 入力と混同される心配がありません。
142
+
143
+ **対応ブラウザ**(新構文 `:state(x)`): Chrome/Edge 125+、Safari 17.4+、Firefox 126+。
144
+ 非対応の環境ではステートが一切 set されないだけです — `:state()` セレクタがマッチしなく
145
+ なりますが、`<wcs-accelerometer>` 自体は通常どおり動作し続けます(graceful degradation・never-throw)。
146
+
147
+ **SSR:** `:state()` は HTML にシリアライズできないため、サーバーレンダリングされた
148
+ マークアップの初期ペイントにはこれらのステートは乗りません(`@wcstack/server` は無改変)。
149
+ ハイドレーション前の見た目を制御したい場合は、代わりに `wcs-accelerometer:not(:defined)` と組み合わせてください。
150
+
151
+ ### デバッグ
152
+
153
+ カスタムステートは DevTools の Elements パネルには表示されず、`attachInternals()`
154
+ は同一要素に 2 回呼べないため、コンソールから直接覗く手段がありません。そのための
155
+ デバッグ専用の補助を 2 つ用意しています:
156
+
157
+ - `el.debugStates` — 現在 on になっているステート名の**スナップショット**配列
158
+ (例: `["error"]`)。`wc-bindable` の一部ではなく(バインド対象ではない)、
159
+ 形状も契約として保証されません — デバッグ用途にのみ使ってください。
160
+ - `debug-states` 属性(opt-in・既定 OFF)は、ステート変化を要素の
161
+ `data-wcs-state-error` 属性にミラーします。
162
+ Elements パネルを開いておけば、トグルのたびにハイライトされます:
163
+
164
+ ```html
165
+ <wcs-accelerometer debug-states></wcs-accelerometer>
166
+ ```
167
+
168
+ **CSS は `data-wcs-state-*` ではなく `:state()` に書いてください。** ミラーされた
169
+ 属性は、DevTools を開いた状態でステート変化を可視化するためだけのものであり、
170
+ スタイリング用の正式なフックではありません。
171
+
120
172
  ## ヘッドレス利用(`AccelerometerCore`)
121
173
 
122
174
  ```typescript
package/README.md CHANGED
@@ -120,6 +120,62 @@ Every bound state path must be declared up front — binding an undeclared path
120
120
  - **Never call the raw `new Accelerometer(...)` anywhere but the one guarded construction helper** — permission denial and Permissions-Policy blocks throw synchronously.
121
121
  - Permission status (`granted`/`denied`/`prompt`) is intentionally not duplicated here — compose with `<wcs-permission name="accelerometer">`.
122
122
 
123
+ ## CSS styling with `:state()`
124
+
125
+ `<wcs-accelerometer>` reflects one boolean output state onto its
126
+ [`ElementInternals` `CustomStateSet`](https://developer.mozilla.org/en-US/docs/Web/API/CustomStateSet),
127
+ so you can style it directly from CSS with the `:state()` pseudo-class — no
128
+ `data-wcs` binding or extra class toggling required. `x`/`y`/`z` (continuous
129
+ sensor readings) are intentionally **not** reflected — see
130
+ `docs/custom-state-reflection-design.md` §3.2.
131
+
132
+ | State | On when |
133
+ |-------|---------|
134
+ | `error` | `wcs-accelerometer:error` fires with a non-`null` detail (cleared on `null`) |
135
+
136
+ ```css
137
+ wcs-accelerometer:state(error) ~ .fallback { display: block; }
138
+ ```
139
+
140
+ Note `error` is sticky (see "Notes & limitations" above): once set, the
141
+ `error` state stays on until a later `wcs-accelerometer:error` event fires
142
+ with a `null` detail — it is not auto-cleared by a subsequent successful
143
+ `start()` or by incoming `reading`s.
144
+
145
+ Unlike attributes or classes, `:state()` cannot be written from outside the
146
+ element, so there is no risk of confusing this output state with an input.
147
+
148
+ **Browser support** (`:state(x)` syntax): Chrome/Edge 125+, Safari 17.4+,
149
+ Firefox 126+. In older browsers the states are simply never set — `:state()`
150
+ selectors never match, but `<wcs-accelerometer>` itself keeps working normally
151
+ (graceful degradation, never-throw).
152
+
153
+ **SSR**: `:state()` cannot be serialized into HTML, so server-rendered markup
154
+ never carries these states on first paint (`@wcstack/server` is unaffected).
155
+ If you need to style the pre-hydration gap, pair your rule with
156
+ `wcs-accelerometer:not(:defined)` instead.
157
+
158
+ ### Debugging
159
+
160
+ Custom states are invisible in DevTools' Elements panel and `attachInternals()`
161
+ cannot be called twice, so there is no console way to inspect them directly.
162
+ Two debug-only aids are provided for that:
163
+
164
+ - `el.debugStates` — a **snapshot** array of the currently-on state names
165
+ (e.g. `["error"]`). It is not part of `wc-bindable` (not a bind target)
166
+ and its shape is not a guaranteed contract — use it for debugging only.
167
+ - The `debug-states` attribute (opt-in, default off) mirrors state changes
168
+ onto a `data-wcs-state-error` attribute on the element, so the Elements
169
+ panel highlights it as it toggles:
170
+
171
+ ```html
172
+ <wcs-accelerometer debug-states></wcs-accelerometer>
173
+ ```
174
+
175
+ **Write your CSS against `:state()`, not `data-wcs-state-*`.** The mirrored
176
+ attribute exists purely to make state changes visible while debugging with
177
+ DevTools open; it is not a supported styling hook.
178
+
123
179
  ## Headless usage (`AccelerometerCore`)
124
180
 
125
181
  ```typescript
package/dist/index.d.ts CHANGED
@@ -188,7 +188,11 @@ declare class WcsAccelerometer extends HTMLElement {
188
188
  static wcBindable: IWcBindable;
189
189
  private _core;
190
190
  private _connectedCallbackPromise;
191
+ private _internals;
191
192
  constructor();
193
+ get debugStates(): string[];
194
+ private _initInternals;
195
+ private _wireStates;
192
196
  /**
193
197
  * Sampling frequency in Hz. Reads back `null` when unset, blank, or when the
194
198
  * attribute does not parse to a positive finite number (NaN, `"0"`, negative)
package/dist/index.esm.js CHANGED
@@ -273,9 +273,62 @@ class WcsAccelerometer extends HTMLElement {
273
273
  };
274
274
  _core;
275
275
  _connectedCallbackPromise = Promise.resolve();
276
+ _internals = null;
276
277
  constructor() {
277
278
  super();
278
279
  this._core = new AccelerometerCore(this);
280
+ this._internals = this._initInternals();
281
+ this._wireStates({
282
+ "wcs-accelerometer:error": (d) => ({ error: d != null }),
283
+ });
284
+ }
285
+ // CSS state reflection (:state()) — debug-only snapshot getter. NOT part of
286
+ // wc-bindable (not a bind target); see README "CSS styling with :state()".
287
+ // MUST NOT return the live CustomStateSet (that would let callers write
288
+ // states from outside, defeating the point of :state() being read-only).
289
+ get debugStates() {
290
+ return this._internals ? [...this._internals.states] : [];
291
+ }
292
+ _initInternals() {
293
+ // never-throw (docs/async-io-node-guidelines.md §3.6): attachInternals is
294
+ // absent in happy-dom / older environments, and pre-125 Chromium rejects
295
+ // non-dashed state names from states.add() (probed and discarded here).
296
+ // Either case silently disables reflection — the component still works,
297
+ // it just doesn't expose :state() selectors.
298
+ try {
299
+ if (typeof this.attachInternals !== "function")
300
+ return null;
301
+ const internals = this.attachInternals();
302
+ internals.states.add("wcs-probe");
303
+ internals.states.delete("wcs-probe");
304
+ return internals;
305
+ }
306
+ catch {
307
+ return null;
308
+ }
309
+ }
310
+ _wireStates(map) {
311
+ if (this._internals === null)
312
+ return;
313
+ const states = this._internals.states;
314
+ for (const [event, toStates] of Object.entries(map)) {
315
+ this.addEventListener(event, (e) => {
316
+ const debug = this.hasAttribute("debug-states");
317
+ for (const [name, on] of Object.entries(toStates(e.detail))) {
318
+ try {
319
+ if (on) {
320
+ states.add(name);
321
+ }
322
+ else {
323
+ states.delete(name);
324
+ }
325
+ }
326
+ catch { /* never-throw */ }
327
+ if (debug)
328
+ this.toggleAttribute(`data-wcs-state-${name}`, on);
329
+ }
330
+ });
331
+ }
279
332
  }
280
333
  // --- Attribute accessors ---
281
334
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"index.esm.js","sources":["../src/config.ts","../src/core/AccelerometerCore.ts","../src/components/Accelerometer.ts","../src/registerComponents.ts","../src/bootstrapAccelerometer.ts"],"sourcesContent":["import { IConfig, IWritableConfig } from \"./types.js\";\n\ninterface IInternalConfig extends IConfig {\n tagNames: {\n accelerometer: string;\n };\n}\n\nconst _config: IInternalConfig = {\n tagNames: {\n accelerometer: \"wcs-accelerometer\",\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 { IWcBindable, WcsAccelerometerReading, WcsAccelerometerErrorDetail } from \"../types.js\";\n\nconst NULL_READING: WcsAccelerometerReading = Object.freeze({ x: null, y: null, z: null });\n\n/**\n * Headless Accelerometer primitive. A thin, framework-agnostic wrapper around\n * the Generic Sensor API's `Accelerometer` class exposed through the\n * wc-bindable protocol.\n *\n * The platform `Sensor` base class (shared by `Accelerometer` / `Gyroscope` /\n * `Magnetometer` / `AmbientLightSensor`) reports failure through an `'error'`\n * event rather than a rejected promise, so this Core can satisfy never-throw\n * (docs/async-io-node-guidelines.md §3.6) by simply forwarding that event —\n * see docs/sensor-tag-design.md §0. The one place a synchronous\n * exception *can* still escape the platform API is the `Accelerometer`\n * constructor itself (e.g. `SecurityError` on permission denial or a\n * feature-policy block); `_createSensor()` wraps that single call in\n * try/catch, mirroring FetchCore's `_doFetch` try/catch around\n * `globalThis.fetch` (packages/fetch/src/core/FetchCore.ts).\n *\n * `x`/`y`/`z` are three getters derived from the single `wcs-accelerometer:reading`\n * event (mirroring how NetworkCore exposes effectiveType/downlink/… from one\n * `wcs-network:change` event): the native `reading` event already reports all\n * three axes together, so they are not split into independent events. `reading`\n * is an event-like signal (a fresh sample every time, not a settled state) and\n * is therefore deliberately NOT same-value guarded — every sample dispatches.\n * `error` is state-like (denial / unsupported does not change from tick to\n * tick) and IS same-value guarded, and is published on its own\n * `wcs-accelerometer:error` event, independent of `reading`.\n *\n * No `_gen` generation guard: start()/stop() are a synchronous\n * subscribe/unsubscribe toggle with no asynchronous probe whose stale\n * resolution could race a dispose() — see docs/sensor-tag-design.md §1.5\n * (the same reasoning as NetworkCore, docs/network-tag-design.md §5).\n *\n * Permissions: this Core does not query `navigator.permissions` itself.\n * Compose with `<wcs-permission name=\"accelerometer\">` instead — see\n * docs/sensor-tag-design.md §\"2番目の決定: Permissions APIとの合成\".\n */\nexport class AccelerometerCore extends EventTarget {\n static wcBindable: IWcBindable = {\n protocol: \"wc-bindable\",\n version: 1,\n properties: [\n { name: \"x\", event: \"wcs-accelerometer:reading\", getter: (e: Event) => (e as CustomEvent).detail.x },\n { name: \"y\", event: \"wcs-accelerometer:reading\", getter: (e: Event) => (e as CustomEvent).detail.y },\n { name: \"z\", event: \"wcs-accelerometer:reading\", getter: (e: Event) => (e as CustomEvent).detail.z },\n { name: \"error\", event: \"wcs-accelerometer:error\" },\n ],\n commands: [{ name: \"start\" }, { name: \"stop\" }],\n };\n\n private _target: EventTarget;\n private _reading: WcsAccelerometerReading = NULL_READING;\n private _error: WcsAccelerometerErrorDetail | null = null;\n\n // The live sensor instance while started (null otherwise), kept so stop()\n // can remove its listeners precisely and so start() can detect \"already\n // started\" without a separate boolean (docs/async-io-node-guidelines.md §3.5\n // idempotency).\n private _sensor: (EventTarget & { start(): void; stop(): void }) | null = null;\n\n constructor(target?: EventTarget) {\n super();\n this._target = target ?? this;\n }\n\n get x(): number | null {\n return this._reading.x;\n }\n\n get y(): number | null {\n return this._reading.y;\n }\n\n get z(): number | null {\n return this._reading.z;\n }\n\n get error(): WcsAccelerometerErrorDetail | null {\n return this._error;\n }\n\n /** No asynchronous probe to await: start()/stop() are synchronous\n * (docs/async-io-node-guidelines.md §3.8 is satisfied trivially, mirroring\n * NetworkCore). */\n get ready(): Promise<void> {\n return Promise.resolve();\n }\n\n // --- State setters ---\n\n // Deliberately NOT same-value guarded: a `reading` is a fresh sample, not a\n // settled state, so it must dispatch every time even when the values happen\n // to repeat (docs/sensor-tag-design.md §1.1).\n private _setReading(reading: WcsAccelerometerReading): void {\n this._reading = reading;\n this._target.dispatchEvent(new CustomEvent(\"wcs-accelerometer:reading\", {\n detail: reading,\n bubbles: true,\n }));\n }\n\n private _setError(error: WcsAccelerometerErrorDetail | null): void {\n // Same-value guard (by error name + message): error is state-like, unlike\n // reading — a repeated identical error (same name and message) must not\n // redispatch.\n if (this._error?.error === error?.error && this._error?.message === error?.message) return;\n this._error = error;\n this._target.dispatchEvent(new CustomEvent(\"wcs-accelerometer:error\", {\n detail: error,\n bubbles: true,\n }));\n }\n\n // --- Public API ---\n\n /**\n * Start the sensor at the given `frequency` (Hz), or the platform default\n * when omitted. Idempotent while already started: a redundant start() does\n * not construct a second sensor instance (which would leak the first).\n * Restart with a different frequency via stop() + start().\n *\n * Synchronous, mirroring the native `Sensor.start()` — never throws\n * (docs/async-io-node-guidelines.md §3.6): both \"unsupported\" and a\n * synchronous constructor exception (permission denial, feature-policy\n * block) are converted to the `error` property instead of propagating.\n */\n start(frequency?: number): void {\n if (this._sensor) return;\n const sensor = this._createSensor(frequency);\n if (!sensor) return;\n sensor.addEventListener(\"reading\", this._onReading as EventListener);\n sensor.addEventListener(\"error\", this._onError as EventListener);\n this._sensor = sensor;\n try {\n sensor.start();\n } catch (e: any) {\n // Defensive: the platform contract says start()/stop() do not throw\n // (failures surface via the 'error' event), but never-throw is a hard\n // requirement here, so guard against a non-conformant implementation\n // too.\n this._teardownSensor();\n this._setError({ error: e?.name ?? \"error\", message: e?.message ?? String(e) });\n }\n }\n\n /** Stop the sensor and detach its listeners. Safe to call when not started. */\n stop(): void {\n if (!this._sensor) return;\n try {\n this._sensor.stop();\n } catch {\n // Never-throw defensive guard, symmetric with start(). Teardown below\n // still runs so listeners are detached regardless.\n }\n this._teardownSensor();\n }\n\n /** Lifecycle alias for start(), so the Shell's connectedCallback can drive\n * this Core the same way as other IO nodes' observe()/dispose() pair. No\n * asynchronous probe, so the returned promise always resolves immediately. */\n observe(frequency?: number): Promise<void> {\n this.start(frequency);\n return this.ready;\n }\n\n /** Lifecycle alias for stop(), invoked from the Shell's disconnectedCallback. */\n dispose(): void {\n this.stop();\n }\n\n // --- Internal ---\n\n // Both call sites (start()'s catch, stop()) only ever invoke this once\n // `this._sensor` is already known non-null, so there is no null-guard here\n // (nothing to defend against).\n private _teardownSensor(): void {\n this._sensor!.removeEventListener(\"reading\", this._onReading as EventListener);\n this._sensor!.removeEventListener(\"error\", this._onError as EventListener);\n this._sensor = null;\n }\n\n /**\n * Construct the platform `Accelerometer`, guarding both non-support and a\n * synchronous constructor exception. Never calls the raw `new Accelerometer(...)`\n * anywhere else in this class — see docs/sensor-tag-design.md §1.5.\n *\n * API resolution is call-time (docs/async-io-node-guidelines.md §3.7):\n * re-checked on every start(), never cached, so tests can install/remove the\n * global freely and an unsupported environment is always reported correctly.\n */\n private _createSensor(frequency?: number): (EventTarget & { start(): void; stop(): void }) | null {\n const Ctor = (globalThis as any).Accelerometer;\n if (typeof Ctor !== \"function\") {\n this._setError({ error: \"unsupported\", message: \"Accelerometer is not supported\" });\n return null;\n }\n try {\n return new Ctor(frequency !== undefined ? { frequency } : undefined);\n } catch (e: any) {\n // SecurityError (permission denial, feature-policy block) or any other\n // synchronous construction failure. Mirrors the FetchCore._doFetch\n // try/catch structure (packages/fetch/src/core/FetchCore.ts) — a\n // synchronous constructor call here instead of an awaited fetch().\n this._setError({ error: e?.name ?? \"error\", message: e?.message ?? String(e) });\n return null;\n }\n }\n\n private _onReading = (event: Event): void => {\n const sensor = event.target as unknown as { x: number | null; y: number | null; z: number | null };\n this._setReading({ x: sensor.x, y: sensor.y, z: sensor.z });\n };\n\n private _onError = (event: Event): void => {\n const err = (event as any).error as { name?: string; message?: string } | undefined;\n // Fallback is a meaningful constant, NOT String(err): a SensorErrorEvent\n // without an `error` field would otherwise stringify `undefined` into the\n // literal message \"undefined\" (aligned across the sensor family).\n this._setError({ error: err?.name ?? \"error\", message: err?.message ?? \"Sensor error\" });\n };\n}\n","import { IWcBindable, WcsAccelerometerErrorDetail } from \"../types.js\";\nimport { AccelerometerCore } from \"../core/AccelerometerCore.js\";\n\n/**\n * `<wcs-accelerometer>` — declarative Generic Sensor API (`Accelerometer`)\n * monitor + start/stop control.\n *\n * Unlike `<wcs-network>` / `<wcs-permission>` (pure monitors), this Shell is a\n * bidirectional node: `start`/`stop` commands (command-token: state → element)\n * alongside the `x`/`y`/`z`/`error` observable surface (event-token: element →\n * state). The `frequency` attribute is the sole configuration input, forwarded\n * to the platform `Accelerometer` constructor's `{ frequency }` option\n * (docs/sensor-tag-design.md §1.2). The getter normalizes it: a non-finite or\n * non-positive value (NaN, 0, negative) reads back as `null` — meaning \"no\n * frequency specified\" — so start() falls back to the platform default rather\n * than forwarding a value the sensor would reject. Any positive finite value is\n * passed through verbatim (no upper-bound clamping — an out-of-range-but-positive\n * rate is still left to the browser/sensor to reject via `error`).\n *\n * Permission handling is intentionally NOT implemented here. Compose with\n * `<wcs-permission name=\"accelerometer\">` instead (see the README's permission\n * example, \"Gate on permission, then start\", and docs/sensor-tag-design.md).\n */\nexport class WcsAccelerometer extends HTMLElement {\n static hasConnectedCallbackPromise = true;\n\n static wcBindable: IWcBindable = {\n ...AccelerometerCore.wcBindable,\n inputs: [{ name: \"frequency\" }],\n // Core の commands をそのまま継承(単一情報源)。\n commands: AccelerometerCore.wcBindable.commands,\n };\n\n private _core: AccelerometerCore;\n private _connectedCallbackPromise: Promise<void> = Promise.resolve();\n\n constructor() {\n super();\n this._core = new AccelerometerCore(this);\n }\n\n // --- Attribute accessors ---\n\n /**\n * Sampling frequency in Hz. Reads back `null` when unset, blank, or when the\n * attribute does not parse to a positive finite number (NaN, `\"0\"`, negative)\n * — in every such \"no usable value\" case the platform default applies.\n *\n * Note the deliberate set/get asymmetry: `set frequency(0)` (or any\n * non-positive/non-finite value) still writes the attribute verbatim for\n * transparency/inspectability, but the getter normalizes it back to `null`.\n * A round-trip through a non-positive value therefore does NOT preserve it —\n * that value carries no valid sampling meaning, so it is treated as \"unset\"\n * on read. Only positive finite frequencies survive a set→get round-trip.\n */\n get frequency(): number | null {\n const attr = this.getAttribute(\"frequency\");\n if (attr === null || attr.trim() === \"\") return null;\n const parsed = Number(attr);\n return Number.isFinite(parsed) && parsed > 0 ? parsed : null;\n }\n\n set frequency(value: number | null | undefined) {\n if (value === null || value === undefined) {\n this.removeAttribute(\"frequency\");\n } else {\n this.setAttribute(\"frequency\", String(value));\n }\n }\n\n // --- Core delegated getters ---\n\n get x(): number | null {\n return this._core.x;\n }\n\n get y(): number | null {\n return this._core.y;\n }\n\n get z(): number | null {\n return this._core.z;\n }\n\n get error(): WcsAccelerometerErrorDetail | null {\n return this._core.error;\n }\n\n get connectedCallbackPromise(): Promise<void> {\n return this._connectedCallbackPromise;\n }\n\n // --- Commands ---\n\n start(): void {\n this._core.start(this.frequency ?? undefined);\n }\n\n stop(): void {\n this._core.stop();\n }\n\n // --- Lifecycle ---\n\n // Deliberately does NOT auto-start the sensor on connect. Unlike\n // Geolocation (whose default phase acquires a fix immediately unless\n // `manual` is set), Accelerometer has no such \"connect implies observing\"\n // precedent in the design doc (docs/sensor-tag-design.md §1.3):\n // start/stop are the only commands, so connecting the element merely makes\n // it inert until a command-token `start` (or the `start()` method) is\n // invoked. This also keeps behavior predictable when composed with\n // `<wcs-permission name=\"accelerometer\">`: the caller decides when to start,\n // typically gated on `granted`.\n connectedCallback(): void {\n this.style.display = \"none\";\n // No asynchronous probe to await (docs/async-io-node-guidelines.md §3.8);\n // kept for SSR uniformity with other IO nodes.\n this._connectedCallbackPromise = this._core.ready;\n }\n\n disconnectedCallback(): void {\n this._core.dispose();\n }\n}\n","import { WcsAccelerometer } from \"./components/Accelerometer.js\";\nimport { config } from \"./config.js\";\n\nexport function registerComponents(): void {\n if (!customElements.get(config.tagNames.accelerometer)) {\n customElements.define(config.tagNames.accelerometer, WcsAccelerometer);\n }\n}\n","import { setConfig } from \"./config.js\";\nimport { registerComponents } from \"./registerComponents.js\";\nimport { IWritableConfig } from \"./types.js\";\n\nexport function bootstrapAccelerometer(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/AccelerometerCore.ts","../src/components/Accelerometer.ts","../src/registerComponents.ts","../src/bootstrapAccelerometer.ts"],"sourcesContent":["import { IConfig, IWritableConfig } from \"./types.js\";\n\ninterface IInternalConfig extends IConfig {\n tagNames: {\n accelerometer: string;\n };\n}\n\nconst _config: IInternalConfig = {\n tagNames: {\n accelerometer: \"wcs-accelerometer\",\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 { IWcBindable, WcsAccelerometerReading, WcsAccelerometerErrorDetail } from \"../types.js\";\n\nconst NULL_READING: WcsAccelerometerReading = Object.freeze({ x: null, y: null, z: null });\n\n/**\n * Headless Accelerometer primitive. A thin, framework-agnostic wrapper around\n * the Generic Sensor API's `Accelerometer` class exposed through the\n * wc-bindable protocol.\n *\n * The platform `Sensor` base class (shared by `Accelerometer` / `Gyroscope` /\n * `Magnetometer` / `AmbientLightSensor`) reports failure through an `'error'`\n * event rather than a rejected promise, so this Core can satisfy never-throw\n * (docs/async-io-node-guidelines.md §3.6) by simply forwarding that event —\n * see docs/sensor-tag-design.md §0. The one place a synchronous\n * exception *can* still escape the platform API is the `Accelerometer`\n * constructor itself (e.g. `SecurityError` on permission denial or a\n * feature-policy block); `_createSensor()` wraps that single call in\n * try/catch, mirroring FetchCore's `_doFetch` try/catch around\n * `globalThis.fetch` (packages/fetch/src/core/FetchCore.ts).\n *\n * `x`/`y`/`z` are three getters derived from the single `wcs-accelerometer:reading`\n * event (mirroring how NetworkCore exposes effectiveType/downlink/… from one\n * `wcs-network:change` event): the native `reading` event already reports all\n * three axes together, so they are not split into independent events. `reading`\n * is an event-like signal (a fresh sample every time, not a settled state) and\n * is therefore deliberately NOT same-value guarded — every sample dispatches.\n * `error` is state-like (denial / unsupported does not change from tick to\n * tick) and IS same-value guarded, and is published on its own\n * `wcs-accelerometer:error` event, independent of `reading`.\n *\n * No `_gen` generation guard: start()/stop() are a synchronous\n * subscribe/unsubscribe toggle with no asynchronous probe whose stale\n * resolution could race a dispose() — see docs/sensor-tag-design.md §1.5\n * (the same reasoning as NetworkCore, docs/network-tag-design.md §5).\n *\n * Permissions: this Core does not query `navigator.permissions` itself.\n * Compose with `<wcs-permission name=\"accelerometer\">` instead — see\n * docs/sensor-tag-design.md §\"2番目の決定: Permissions APIとの合成\".\n */\nexport class AccelerometerCore extends EventTarget {\n static wcBindable: IWcBindable = {\n protocol: \"wc-bindable\",\n version: 1,\n properties: [\n { name: \"x\", event: \"wcs-accelerometer:reading\", getter: (e: Event) => (e as CustomEvent).detail.x },\n { name: \"y\", event: \"wcs-accelerometer:reading\", getter: (e: Event) => (e as CustomEvent).detail.y },\n { name: \"z\", event: \"wcs-accelerometer:reading\", getter: (e: Event) => (e as CustomEvent).detail.z },\n { name: \"error\", event: \"wcs-accelerometer:error\" },\n ],\n commands: [{ name: \"start\" }, { name: \"stop\" }],\n };\n\n private _target: EventTarget;\n private _reading: WcsAccelerometerReading = NULL_READING;\n private _error: WcsAccelerometerErrorDetail | null = null;\n\n // The live sensor instance while started (null otherwise), kept so stop()\n // can remove its listeners precisely and so start() can detect \"already\n // started\" without a separate boolean (docs/async-io-node-guidelines.md §3.5\n // idempotency).\n private _sensor: (EventTarget & { start(): void; stop(): void }) | null = null;\n\n constructor(target?: EventTarget) {\n super();\n this._target = target ?? this;\n }\n\n get x(): number | null {\n return this._reading.x;\n }\n\n get y(): number | null {\n return this._reading.y;\n }\n\n get z(): number | null {\n return this._reading.z;\n }\n\n get error(): WcsAccelerometerErrorDetail | null {\n return this._error;\n }\n\n /** No asynchronous probe to await: start()/stop() are synchronous\n * (docs/async-io-node-guidelines.md §3.8 is satisfied trivially, mirroring\n * NetworkCore). */\n get ready(): Promise<void> {\n return Promise.resolve();\n }\n\n // --- State setters ---\n\n // Deliberately NOT same-value guarded: a `reading` is a fresh sample, not a\n // settled state, so it must dispatch every time even when the values happen\n // to repeat (docs/sensor-tag-design.md §1.1).\n private _setReading(reading: WcsAccelerometerReading): void {\n this._reading = reading;\n this._target.dispatchEvent(new CustomEvent(\"wcs-accelerometer:reading\", {\n detail: reading,\n bubbles: true,\n }));\n }\n\n private _setError(error: WcsAccelerometerErrorDetail | null): void {\n // Same-value guard (by error name + message): error is state-like, unlike\n // reading — a repeated identical error (same name and message) must not\n // redispatch.\n if (this._error?.error === error?.error && this._error?.message === error?.message) return;\n this._error = error;\n this._target.dispatchEvent(new CustomEvent(\"wcs-accelerometer:error\", {\n detail: error,\n bubbles: true,\n }));\n }\n\n // --- Public API ---\n\n /**\n * Start the sensor at the given `frequency` (Hz), or the platform default\n * when omitted. Idempotent while already started: a redundant start() does\n * not construct a second sensor instance (which would leak the first).\n * Restart with a different frequency via stop() + start().\n *\n * Synchronous, mirroring the native `Sensor.start()` — never throws\n * (docs/async-io-node-guidelines.md §3.6): both \"unsupported\" and a\n * synchronous constructor exception (permission denial, feature-policy\n * block) are converted to the `error` property instead of propagating.\n */\n start(frequency?: number): void {\n if (this._sensor) return;\n const sensor = this._createSensor(frequency);\n if (!sensor) return;\n sensor.addEventListener(\"reading\", this._onReading as EventListener);\n sensor.addEventListener(\"error\", this._onError as EventListener);\n this._sensor = sensor;\n try {\n sensor.start();\n } catch (e: any) {\n // Defensive: the platform contract says start()/stop() do not throw\n // (failures surface via the 'error' event), but never-throw is a hard\n // requirement here, so guard against a non-conformant implementation\n // too.\n this._teardownSensor();\n this._setError({ error: e?.name ?? \"error\", message: e?.message ?? String(e) });\n }\n }\n\n /** Stop the sensor and detach its listeners. Safe to call when not started. */\n stop(): void {\n if (!this._sensor) return;\n try {\n this._sensor.stop();\n } catch {\n // Never-throw defensive guard, symmetric with start(). Teardown below\n // still runs so listeners are detached regardless.\n }\n this._teardownSensor();\n }\n\n /** Lifecycle alias for start(), so the Shell's connectedCallback can drive\n * this Core the same way as other IO nodes' observe()/dispose() pair. No\n * asynchronous probe, so the returned promise always resolves immediately. */\n observe(frequency?: number): Promise<void> {\n this.start(frequency);\n return this.ready;\n }\n\n /** Lifecycle alias for stop(), invoked from the Shell's disconnectedCallback. */\n dispose(): void {\n this.stop();\n }\n\n // --- Internal ---\n\n // Both call sites (start()'s catch, stop()) only ever invoke this once\n // `this._sensor` is already known non-null, so there is no null-guard here\n // (nothing to defend against).\n private _teardownSensor(): void {\n this._sensor!.removeEventListener(\"reading\", this._onReading as EventListener);\n this._sensor!.removeEventListener(\"error\", this._onError as EventListener);\n this._sensor = null;\n }\n\n /**\n * Construct the platform `Accelerometer`, guarding both non-support and a\n * synchronous constructor exception. Never calls the raw `new Accelerometer(...)`\n * anywhere else in this class — see docs/sensor-tag-design.md §1.5.\n *\n * API resolution is call-time (docs/async-io-node-guidelines.md §3.7):\n * re-checked on every start(), never cached, so tests can install/remove the\n * global freely and an unsupported environment is always reported correctly.\n */\n private _createSensor(frequency?: number): (EventTarget & { start(): void; stop(): void }) | null {\n const Ctor = (globalThis as any).Accelerometer;\n if (typeof Ctor !== \"function\") {\n this._setError({ error: \"unsupported\", message: \"Accelerometer is not supported\" });\n return null;\n }\n try {\n return new Ctor(frequency !== undefined ? { frequency } : undefined);\n } catch (e: any) {\n // SecurityError (permission denial, feature-policy block) or any other\n // synchronous construction failure. Mirrors the FetchCore._doFetch\n // try/catch structure (packages/fetch/src/core/FetchCore.ts) — a\n // synchronous constructor call here instead of an awaited fetch().\n this._setError({ error: e?.name ?? \"error\", message: e?.message ?? String(e) });\n return null;\n }\n }\n\n private _onReading = (event: Event): void => {\n const sensor = event.target as unknown as { x: number | null; y: number | null; z: number | null };\n this._setReading({ x: sensor.x, y: sensor.y, z: sensor.z });\n };\n\n private _onError = (event: Event): void => {\n const err = (event as any).error as { name?: string; message?: string } | undefined;\n // Fallback is a meaningful constant, NOT String(err): a SensorErrorEvent\n // without an `error` field would otherwise stringify `undefined` into the\n // literal message \"undefined\" (aligned across the sensor family).\n this._setError({ error: err?.name ?? \"error\", message: err?.message ?? \"Sensor error\" });\n };\n}\n","import { IWcBindable, WcsAccelerometerErrorDetail } from \"../types.js\";\nimport { AccelerometerCore } from \"../core/AccelerometerCore.js\";\n\n/**\n * `<wcs-accelerometer>` — declarative Generic Sensor API (`Accelerometer`)\n * monitor + start/stop control.\n *\n * Unlike `<wcs-network>` / `<wcs-permission>` (pure monitors), this Shell is a\n * bidirectional node: `start`/`stop` commands (command-token: state → element)\n * alongside the `x`/`y`/`z`/`error` observable surface (event-token: element →\n * state). The `frequency` attribute is the sole configuration input, forwarded\n * to the platform `Accelerometer` constructor's `{ frequency }` option\n * (docs/sensor-tag-design.md §1.2). The getter normalizes it: a non-finite or\n * non-positive value (NaN, 0, negative) reads back as `null` — meaning \"no\n * frequency specified\" — so start() falls back to the platform default rather\n * than forwarding a value the sensor would reject. Any positive finite value is\n * passed through verbatim (no upper-bound clamping — an out-of-range-but-positive\n * rate is still left to the browser/sensor to reject via `error`).\n *\n * Permission handling is intentionally NOT implemented here. Compose with\n * `<wcs-permission name=\"accelerometer\">` instead (see the README's permission\n * example, \"Gate on permission, then start\", and docs/sensor-tag-design.md).\n */\nexport class WcsAccelerometer extends HTMLElement {\n static hasConnectedCallbackPromise = true;\n\n static wcBindable: IWcBindable = {\n ...AccelerometerCore.wcBindable,\n inputs: [{ name: \"frequency\" }],\n // Core の commands をそのまま継承(単一情報源)。\n commands: AccelerometerCore.wcBindable.commands,\n };\n\n private _core: AccelerometerCore;\n private _connectedCallbackPromise: Promise<void> = Promise.resolve();\n private _internals: ElementInternals | null = null;\n\n constructor() {\n super();\n this._core = new AccelerometerCore(this);\n this._internals = this._initInternals();\n this._wireStates({\n \"wcs-accelerometer: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/async-io-node-guidelines.md §3.6): attachInternals is\n // 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 * Sampling frequency in Hz. Reads back `null` when unset, blank, or when the\n * attribute does not parse to a positive finite number (NaN, `\"0\"`, negative)\n * — in every such \"no usable value\" case the platform default applies.\n *\n * Note the deliberate set/get asymmetry: `set frequency(0)` (or any\n * non-positive/non-finite value) still writes the attribute verbatim for\n * transparency/inspectability, but the getter normalizes it back to `null`.\n * A round-trip through a non-positive value therefore does NOT preserve it —\n * that value carries no valid sampling meaning, so it is treated as \"unset\"\n * on read. Only positive finite frequencies survive a set→get round-trip.\n */\n get frequency(): number | null {\n const attr = this.getAttribute(\"frequency\");\n if (attr === null || attr.trim() === \"\") return null;\n const parsed = Number(attr);\n return Number.isFinite(parsed) && parsed > 0 ? parsed : null;\n }\n\n set frequency(value: number | null | undefined) {\n if (value === null || value === undefined) {\n this.removeAttribute(\"frequency\");\n } else {\n this.setAttribute(\"frequency\", String(value));\n }\n }\n\n // --- Core delegated getters ---\n\n get x(): number | null {\n return this._core.x;\n }\n\n get y(): number | null {\n return this._core.y;\n }\n\n get z(): number | null {\n return this._core.z;\n }\n\n get error(): WcsAccelerometerErrorDetail | null {\n return this._core.error;\n }\n\n get connectedCallbackPromise(): Promise<void> {\n return this._connectedCallbackPromise;\n }\n\n // --- Commands ---\n\n start(): void {\n this._core.start(this.frequency ?? undefined);\n }\n\n stop(): void {\n this._core.stop();\n }\n\n // --- Lifecycle ---\n\n // Deliberately does NOT auto-start the sensor on connect. Unlike\n // Geolocation (whose default phase acquires a fix immediately unless\n // `manual` is set), Accelerometer has no such \"connect implies observing\"\n // precedent in the design doc (docs/sensor-tag-design.md §1.3):\n // start/stop are the only commands, so connecting the element merely makes\n // it inert until a command-token `start` (or the `start()` method) is\n // invoked. This also keeps behavior predictable when composed with\n // `<wcs-permission name=\"accelerometer\">`: the caller decides when to start,\n // typically gated on `granted`.\n connectedCallback(): void {\n this.style.display = \"none\";\n // No asynchronous probe to await (docs/async-io-node-guidelines.md §3.8);\n // kept for SSR uniformity with other IO nodes.\n this._connectedCallbackPromise = this._core.ready;\n }\n\n disconnectedCallback(): void {\n this._core.dispose();\n }\n}\n","import { WcsAccelerometer } from \"./components/Accelerometer.js\";\nimport { config } from \"./config.js\";\n\nexport function registerComponents(): void {\n if (!customElements.get(config.tagNames.accelerometer)) {\n customElements.define(config.tagNames.accelerometer, WcsAccelerometer);\n }\n}\n","import { setConfig } from \"./config.js\";\nimport { registerComponents } from \"./registerComponents.js\";\nimport { IWritableConfig } from \"./types.js\";\n\nexport function bootstrapAccelerometer(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:{accelerometer:"wcs-accelerometer"}};function r(e){if(null===e||"object"!=typeof e)return e;Object.freeze(e);for(const t of Object.keys(e))r(e[t]);return e}function t(e){if(null===e||"object"!=typeof e)return e;const r={};for(const s of Object.keys(e))r[s]=t(e[s]);return r}let s=null;const n=e;function o(){return s||(s=r(t(e))),s}const i=Object.freeze({x:null,y:null,z:null});class c extends EventTarget{static wcBindable={protocol:"wc-bindable",version:1,properties:[{name:"x",event:"wcs-accelerometer:reading",getter:e=>e.detail.x},{name:"y",event:"wcs-accelerometer:reading",getter:e=>e.detail.y},{name:"z",event:"wcs-accelerometer:reading",getter:e=>e.detail.z},{name:"error",event:"wcs-accelerometer:error"}],commands:[{name:"start"},{name:"stop"}]};_target;_reading=i;_error=null;_sensor=null;constructor(e){super(),this._target=e??this}get x(){return this._reading.x}get y(){return this._reading.y}get z(){return this._reading.z}get error(){return this._error}get ready(){return Promise.resolve()}_setReading(e){this._reading=e,this._target.dispatchEvent(new CustomEvent("wcs-accelerometer:reading",{detail:e,bubbles:!0}))}_setError(e){this._error?.error===e?.error&&this._error?.message===e?.message||(this._error=e,this._target.dispatchEvent(new CustomEvent("wcs-accelerometer:error",{detail:e,bubbles:!0})))}start(e){if(this._sensor)return;const r=this._createSensor(e);if(r){r.addEventListener("reading",this._onReading),r.addEventListener("error",this._onError),this._sensor=r;try{r.start()}catch(e){this._teardownSensor(),this._setError({error:e?.name??"error",message:e?.message??String(e)})}}}stop(){if(this._sensor){try{this._sensor.stop()}catch{}this._teardownSensor()}}observe(e){return this.start(e),this.ready}dispose(){this.stop()}_teardownSensor(){this._sensor.removeEventListener("reading",this._onReading),this._sensor.removeEventListener("error",this._onError),this._sensor=null}_createSensor(e){const r=globalThis.Accelerometer;if("function"!=typeof r)return this._setError({error:"unsupported",message:"Accelerometer is not supported"}),null;try{return new r(void 0!==e?{frequency:e}:void 0)}catch(e){return this._setError({error:e?.name??"error",message:e?.message??String(e)}),null}}_onReading=e=>{const r=e.target;this._setReading({x:r.x,y:r.y,z:r.z})};_onError=e=>{const r=e.error;this._setError({error:r?.name??"error",message:r?.message??"Sensor error"})}}class a extends HTMLElement{static hasConnectedCallbackPromise=!0;static wcBindable={...c.wcBindable,inputs:[{name:"frequency"}],commands:c.wcBindable.commands};_core;_connectedCallbackPromise=Promise.resolve();constructor(){super(),this._core=new c(this)}get frequency(){const e=this.getAttribute("frequency");if(null===e||""===e.trim())return null;const r=Number(e);return Number.isFinite(r)&&r>0?r:null}set frequency(e){null==e?this.removeAttribute("frequency"):this.setAttribute("frequency",String(e))}get x(){return this._core.x}get y(){return this._core.y}get z(){return this._core.z}get error(){return this._core.error}get connectedCallbackPromise(){return this._connectedCallbackPromise}start(){this._core.start(this.frequency??void 0)}stop(){this._core.stop()}connectedCallback(){this.style.display="none",this._connectedCallbackPromise=this._core.ready}disconnectedCallback(){this._core.dispose()}}function l(r){var t;r&&((t=r).tagNames&&Object.assign(e.tagNames,t.tagNames),s=null),customElements.get(n.tagNames.accelerometer)||customElements.define(n.tagNames.accelerometer,a)}export{c as AccelerometerCore,a as WcsAccelerometer,l as bootstrapAccelerometer,o as getConfig};
1
+ const e={tagNames:{accelerometer:"wcs-accelerometer"}};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 o(){return s||(s=t(r(e))),s}const i=Object.freeze({x:null,y:null,z:null});class a extends EventTarget{static wcBindable={protocol:"wc-bindable",version:1,properties:[{name:"x",event:"wcs-accelerometer:reading",getter:e=>e.detail.x},{name:"y",event:"wcs-accelerometer:reading",getter:e=>e.detail.y},{name:"z",event:"wcs-accelerometer:reading",getter:e=>e.detail.z},{name:"error",event:"wcs-accelerometer:error"}],commands:[{name:"start"},{name:"stop"}]};_target;_reading=i;_error=null;_sensor=null;constructor(e){super(),this._target=e??this}get x(){return this._reading.x}get y(){return this._reading.y}get z(){return this._reading.z}get error(){return this._error}get ready(){return Promise.resolve()}_setReading(e){this._reading=e,this._target.dispatchEvent(new CustomEvent("wcs-accelerometer:reading",{detail:e,bubbles:!0}))}_setError(e){this._error?.error===e?.error&&this._error?.message===e?.message||(this._error=e,this._target.dispatchEvent(new CustomEvent("wcs-accelerometer:error",{detail:e,bubbles:!0})))}start(e){if(this._sensor)return;const t=this._createSensor(e);if(t){t.addEventListener("reading",this._onReading),t.addEventListener("error",this._onError),this._sensor=t;try{t.start()}catch(e){this._teardownSensor(),this._setError({error:e?.name??"error",message:e?.message??String(e)})}}}stop(){if(this._sensor){try{this._sensor.stop()}catch{}this._teardownSensor()}}observe(e){return this.start(e),this.ready}dispose(){this.stop()}_teardownSensor(){this._sensor.removeEventListener("reading",this._onReading),this._sensor.removeEventListener("error",this._onError),this._sensor=null}_createSensor(e){const t=globalThis.Accelerometer;if("function"!=typeof t)return this._setError({error:"unsupported",message:"Accelerometer is not supported"}),null;try{return new t(void 0!==e?{frequency:e}:void 0)}catch(e){return this._setError({error:e?.name??"error",message:e?.message??String(e)}),null}}_onReading=e=>{const t=e.target;this._setReading({x:t.x,y:t.y,z:t.z})};_onError=e=>{const t=e.error;this._setError({error:t?.name??"error",message:t?.message??"Sensor error"})}}class c extends HTMLElement{static hasConnectedCallbackPromise=!0;static wcBindable={...a.wcBindable,inputs:[{name:"frequency"}],commands:a.wcBindable.commands};_core;_connectedCallbackPromise=Promise.resolve();_internals=null;constructor(){super(),this._core=new a(this),this._internals=this._initInternals(),this._wireStates({"wcs-accelerometer:error":e=>({error:null!=e})})}get debugStates(){return this._internals?[...this._internals.states]:[]}_initInternals(){try{if("function"!=typeof this.attachInternals)return null;const e=this.attachInternals();return e.states.add("wcs-probe"),e.states.delete("wcs-probe"),e}catch{return null}}_wireStates(e){if(null===this._internals)return;const t=this._internals.states;for(const[r,s]of Object.entries(e))this.addEventListener(r,e=>{const r=this.hasAttribute("debug-states");for(const[n,o]of Object.entries(s(e.detail))){try{o?t.add(n):t.delete(n)}catch{}r&&this.toggleAttribute(`data-wcs-state-${n}`,o)}})}get frequency(){const e=this.getAttribute("frequency");if(null===e||""===e.trim())return null;const t=Number(e);return Number.isFinite(t)&&t>0?t:null}set frequency(e){null==e?this.removeAttribute("frequency"):this.setAttribute("frequency",String(e))}get x(){return this._core.x}get y(){return this._core.y}get z(){return this._core.z}get error(){return this._core.error}get connectedCallbackPromise(){return this._connectedCallbackPromise}start(){this._core.start(this.frequency??void 0)}stop(){this._core.stop()}connectedCallback(){this.style.display="none",this._connectedCallbackPromise=this._core.ready}disconnectedCallback(){this._core.dispose()}}function l(t){var r;t&&((r=t).tagNames&&Object.assign(e.tagNames,r.tagNames),s=null),customElements.get(n.tagNames.accelerometer)||customElements.define(n.tagNames.accelerometer,c)}export{a as AccelerometerCore,c as WcsAccelerometer,l as bootstrapAccelerometer,o 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/AccelerometerCore.ts","../src/components/Accelerometer.ts","../src/bootstrapAccelerometer.ts","../src/registerComponents.ts"],"sourcesContent":["import { IConfig, IWritableConfig } from \"./types.js\";\n\ninterface IInternalConfig extends IConfig {\n tagNames: {\n accelerometer: string;\n };\n}\n\nconst _config: IInternalConfig = {\n tagNames: {\n accelerometer: \"wcs-accelerometer\",\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 { IWcBindable, WcsAccelerometerReading, WcsAccelerometerErrorDetail } from \"../types.js\";\n\nconst NULL_READING: WcsAccelerometerReading = Object.freeze({ x: null, y: null, z: null });\n\n/**\n * Headless Accelerometer primitive. A thin, framework-agnostic wrapper around\n * the Generic Sensor API's `Accelerometer` class exposed through the\n * wc-bindable protocol.\n *\n * The platform `Sensor` base class (shared by `Accelerometer` / `Gyroscope` /\n * `Magnetometer` / `AmbientLightSensor`) reports failure through an `'error'`\n * event rather than a rejected promise, so this Core can satisfy never-throw\n * (docs/async-io-node-guidelines.md §3.6) by simply forwarding that event —\n * see docs/sensor-tag-design.md §0. The one place a synchronous\n * exception *can* still escape the platform API is the `Accelerometer`\n * constructor itself (e.g. `SecurityError` on permission denial or a\n * feature-policy block); `_createSensor()` wraps that single call in\n * try/catch, mirroring FetchCore's `_doFetch` try/catch around\n * `globalThis.fetch` (packages/fetch/src/core/FetchCore.ts).\n *\n * `x`/`y`/`z` are three getters derived from the single `wcs-accelerometer:reading`\n * event (mirroring how NetworkCore exposes effectiveType/downlink/… from one\n * `wcs-network:change` event): the native `reading` event already reports all\n * three axes together, so they are not split into independent events. `reading`\n * is an event-like signal (a fresh sample every time, not a settled state) and\n * is therefore deliberately NOT same-value guarded — every sample dispatches.\n * `error` is state-like (denial / unsupported does not change from tick to\n * tick) and IS same-value guarded, and is published on its own\n * `wcs-accelerometer:error` event, independent of `reading`.\n *\n * No `_gen` generation guard: start()/stop() are a synchronous\n * subscribe/unsubscribe toggle with no asynchronous probe whose stale\n * resolution could race a dispose() — see docs/sensor-tag-design.md §1.5\n * (the same reasoning as NetworkCore, docs/network-tag-design.md §5).\n *\n * Permissions: this Core does not query `navigator.permissions` itself.\n * Compose with `<wcs-permission name=\"accelerometer\">` instead — see\n * docs/sensor-tag-design.md §\"2番目の決定: Permissions APIとの合成\".\n */\nexport class AccelerometerCore extends EventTarget {\n static wcBindable: IWcBindable = {\n protocol: \"wc-bindable\",\n version: 1,\n properties: [\n { name: \"x\", event: \"wcs-accelerometer:reading\", getter: (e: Event) => (e as CustomEvent).detail.x },\n { name: \"y\", event: \"wcs-accelerometer:reading\", getter: (e: Event) => (e as CustomEvent).detail.y },\n { name: \"z\", event: \"wcs-accelerometer:reading\", getter: (e: Event) => (e as CustomEvent).detail.z },\n { name: \"error\", event: \"wcs-accelerometer:error\" },\n ],\n commands: [{ name: \"start\" }, { name: \"stop\" }],\n };\n\n private _target: EventTarget;\n private _reading: WcsAccelerometerReading = NULL_READING;\n private _error: WcsAccelerometerErrorDetail | null = null;\n\n // The live sensor instance while started (null otherwise), kept so stop()\n // can remove its listeners precisely and so start() can detect \"already\n // started\" without a separate boolean (docs/async-io-node-guidelines.md §3.5\n // idempotency).\n private _sensor: (EventTarget & { start(): void; stop(): void }) | null = null;\n\n constructor(target?: EventTarget) {\n super();\n this._target = target ?? this;\n }\n\n get x(): number | null {\n return this._reading.x;\n }\n\n get y(): number | null {\n return this._reading.y;\n }\n\n get z(): number | null {\n return this._reading.z;\n }\n\n get error(): WcsAccelerometerErrorDetail | null {\n return this._error;\n }\n\n /** No asynchronous probe to await: start()/stop() are synchronous\n * (docs/async-io-node-guidelines.md §3.8 is satisfied trivially, mirroring\n * NetworkCore). */\n get ready(): Promise<void> {\n return Promise.resolve();\n }\n\n // --- State setters ---\n\n // Deliberately NOT same-value guarded: a `reading` is a fresh sample, not a\n // settled state, so it must dispatch every time even when the values happen\n // to repeat (docs/sensor-tag-design.md §1.1).\n private _setReading(reading: WcsAccelerometerReading): void {\n this._reading = reading;\n this._target.dispatchEvent(new CustomEvent(\"wcs-accelerometer:reading\", {\n detail: reading,\n bubbles: true,\n }));\n }\n\n private _setError(error: WcsAccelerometerErrorDetail | null): void {\n // Same-value guard (by error name + message): error is state-like, unlike\n // reading — a repeated identical error (same name and message) must not\n // redispatch.\n if (this._error?.error === error?.error && this._error?.message === error?.message) return;\n this._error = error;\n this._target.dispatchEvent(new CustomEvent(\"wcs-accelerometer:error\", {\n detail: error,\n bubbles: true,\n }));\n }\n\n // --- Public API ---\n\n /**\n * Start the sensor at the given `frequency` (Hz), or the platform default\n * when omitted. Idempotent while already started: a redundant start() does\n * not construct a second sensor instance (which would leak the first).\n * Restart with a different frequency via stop() + start().\n *\n * Synchronous, mirroring the native `Sensor.start()` — never throws\n * (docs/async-io-node-guidelines.md §3.6): both \"unsupported\" and a\n * synchronous constructor exception (permission denial, feature-policy\n * block) are converted to the `error` property instead of propagating.\n */\n start(frequency?: number): void {\n if (this._sensor) return;\n const sensor = this._createSensor(frequency);\n if (!sensor) return;\n sensor.addEventListener(\"reading\", this._onReading as EventListener);\n sensor.addEventListener(\"error\", this._onError as EventListener);\n this._sensor = sensor;\n try {\n sensor.start();\n } catch (e: any) {\n // Defensive: the platform contract says start()/stop() do not throw\n // (failures surface via the 'error' event), but never-throw is a hard\n // requirement here, so guard against a non-conformant implementation\n // too.\n this._teardownSensor();\n this._setError({ error: e?.name ?? \"error\", message: e?.message ?? String(e) });\n }\n }\n\n /** Stop the sensor and detach its listeners. Safe to call when not started. */\n stop(): void {\n if (!this._sensor) return;\n try {\n this._sensor.stop();\n } catch {\n // Never-throw defensive guard, symmetric with start(). Teardown below\n // still runs so listeners are detached regardless.\n }\n this._teardownSensor();\n }\n\n /** Lifecycle alias for start(), so the Shell's connectedCallback can drive\n * this Core the same way as other IO nodes' observe()/dispose() pair. No\n * asynchronous probe, so the returned promise always resolves immediately. */\n observe(frequency?: number): Promise<void> {\n this.start(frequency);\n return this.ready;\n }\n\n /** Lifecycle alias for stop(), invoked from the Shell's disconnectedCallback. */\n dispose(): void {\n this.stop();\n }\n\n // --- Internal ---\n\n // Both call sites (start()'s catch, stop()) only ever invoke this once\n // `this._sensor` is already known non-null, so there is no null-guard here\n // (nothing to defend against).\n private _teardownSensor(): void {\n this._sensor!.removeEventListener(\"reading\", this._onReading as EventListener);\n this._sensor!.removeEventListener(\"error\", this._onError as EventListener);\n this._sensor = null;\n }\n\n /**\n * Construct the platform `Accelerometer`, guarding both non-support and a\n * synchronous constructor exception. Never calls the raw `new Accelerometer(...)`\n * anywhere else in this class — see docs/sensor-tag-design.md §1.5.\n *\n * API resolution is call-time (docs/async-io-node-guidelines.md §3.7):\n * re-checked on every start(), never cached, so tests can install/remove the\n * global freely and an unsupported environment is always reported correctly.\n */\n private _createSensor(frequency?: number): (EventTarget & { start(): void; stop(): void }) | null {\n const Ctor = (globalThis as any).Accelerometer;\n if (typeof Ctor !== \"function\") {\n this._setError({ error: \"unsupported\", message: \"Accelerometer is not supported\" });\n return null;\n }\n try {\n return new Ctor(frequency !== undefined ? { frequency } : undefined);\n } catch (e: any) {\n // SecurityError (permission denial, feature-policy block) or any other\n // synchronous construction failure. Mirrors the FetchCore._doFetch\n // try/catch structure (packages/fetch/src/core/FetchCore.ts) — a\n // synchronous constructor call here instead of an awaited fetch().\n this._setError({ error: e?.name ?? \"error\", message: e?.message ?? String(e) });\n return null;\n }\n }\n\n private _onReading = (event: Event): void => {\n const sensor = event.target as unknown as { x: number | null; y: number | null; z: number | null };\n this._setReading({ x: sensor.x, y: sensor.y, z: sensor.z });\n };\n\n private _onError = (event: Event): void => {\n const err = (event as any).error as { name?: string; message?: string } | undefined;\n // Fallback is a meaningful constant, NOT String(err): a SensorErrorEvent\n // without an `error` field would otherwise stringify `undefined` into the\n // literal message \"undefined\" (aligned across the sensor family).\n this._setError({ error: err?.name ?? \"error\", message: err?.message ?? \"Sensor error\" });\n };\n}\n","import { IWcBindable, WcsAccelerometerErrorDetail } from \"../types.js\";\nimport { AccelerometerCore } from \"../core/AccelerometerCore.js\";\n\n/**\n * `<wcs-accelerometer>` — declarative Generic Sensor API (`Accelerometer`)\n * monitor + start/stop control.\n *\n * Unlike `<wcs-network>` / `<wcs-permission>` (pure monitors), this Shell is a\n * bidirectional node: `start`/`stop` commands (command-token: state → element)\n * alongside the `x`/`y`/`z`/`error` observable surface (event-token: element →\n * state). The `frequency` attribute is the sole configuration input, forwarded\n * to the platform `Accelerometer` constructor's `{ frequency }` option\n * (docs/sensor-tag-design.md §1.2). The getter normalizes it: a non-finite or\n * non-positive value (NaN, 0, negative) reads back as `null` — meaning \"no\n * frequency specified\" — so start() falls back to the platform default rather\n * than forwarding a value the sensor would reject. Any positive finite value is\n * passed through verbatim (no upper-bound clamping — an out-of-range-but-positive\n * rate is still left to the browser/sensor to reject via `error`).\n *\n * Permission handling is intentionally NOT implemented here. Compose with\n * `<wcs-permission name=\"accelerometer\">` instead (see the README's permission\n * example, \"Gate on permission, then start\", and docs/sensor-tag-design.md).\n */\nexport class WcsAccelerometer extends HTMLElement {\n static hasConnectedCallbackPromise = true;\n\n static wcBindable: IWcBindable = {\n ...AccelerometerCore.wcBindable,\n inputs: [{ name: \"frequency\" }],\n // Core の commands をそのまま継承(単一情報源)。\n commands: AccelerometerCore.wcBindable.commands,\n };\n\n private _core: AccelerometerCore;\n private _connectedCallbackPromise: Promise<void> = Promise.resolve();\n\n constructor() {\n super();\n this._core = new AccelerometerCore(this);\n }\n\n // --- Attribute accessors ---\n\n /**\n * Sampling frequency in Hz. Reads back `null` when unset, blank, or when the\n * attribute does not parse to a positive finite number (NaN, `\"0\"`, negative)\n * — in every such \"no usable value\" case the platform default applies.\n *\n * Note the deliberate set/get asymmetry: `set frequency(0)` (or any\n * non-positive/non-finite value) still writes the attribute verbatim for\n * transparency/inspectability, but the getter normalizes it back to `null`.\n * A round-trip through a non-positive value therefore does NOT preserve it —\n * that value carries no valid sampling meaning, so it is treated as \"unset\"\n * on read. Only positive finite frequencies survive a set→get round-trip.\n */\n get frequency(): number | null {\n const attr = this.getAttribute(\"frequency\");\n if (attr === null || attr.trim() === \"\") return null;\n const parsed = Number(attr);\n return Number.isFinite(parsed) && parsed > 0 ? parsed : null;\n }\n\n set frequency(value: number | null | undefined) {\n if (value === null || value === undefined) {\n this.removeAttribute(\"frequency\");\n } else {\n this.setAttribute(\"frequency\", String(value));\n }\n }\n\n // --- Core delegated getters ---\n\n get x(): number | null {\n return this._core.x;\n }\n\n get y(): number | null {\n return this._core.y;\n }\n\n get z(): number | null {\n return this._core.z;\n }\n\n get error(): WcsAccelerometerErrorDetail | null {\n return this._core.error;\n }\n\n get connectedCallbackPromise(): Promise<void> {\n return this._connectedCallbackPromise;\n }\n\n // --- Commands ---\n\n start(): void {\n this._core.start(this.frequency ?? undefined);\n }\n\n stop(): void {\n this._core.stop();\n }\n\n // --- Lifecycle ---\n\n // Deliberately does NOT auto-start the sensor on connect. Unlike\n // Geolocation (whose default phase acquires a fix immediately unless\n // `manual` is set), Accelerometer has no such \"connect implies observing\"\n // precedent in the design doc (docs/sensor-tag-design.md §1.3):\n // start/stop are the only commands, so connecting the element merely makes\n // it inert until a command-token `start` (or the `start()` method) is\n // invoked. This also keeps behavior predictable when composed with\n // `<wcs-permission name=\"accelerometer\">`: the caller decides when to start,\n // typically gated on `granted`.\n connectedCallback(): void {\n this.style.display = \"none\";\n // No asynchronous probe to await (docs/async-io-node-guidelines.md §3.8);\n // kept for SSR uniformity with other IO nodes.\n this._connectedCallbackPromise = this._core.ready;\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 bootstrapAccelerometer(userConfig?: IWritableConfig): void {\n if (userConfig) {\n setConfig(userConfig);\n }\n registerComponents();\n}\n","import { WcsAccelerometer } from \"./components/Accelerometer.js\";\nimport { config } from \"./config.js\";\n\nexport function registerComponents(): void {\n if (!customElements.get(config.tagNames.accelerometer)) {\n customElements.define(config.tagNames.accelerometer, WcsAccelerometer);\n }\n}\n"],"names":["_config","tagNames","accelerometer","deepFreeze","obj","Object","freeze","key","keys","deepClone","clone","frozenConfig","config","getConfig","NULL_READING","x","y","z","AccelerometerCore","EventTarget","static","protocol","version","properties","name","event","getter","e","detail","commands","_target","_reading","_error","_sensor","constructor","target","super","this","error","ready","Promise","resolve","_setReading","reading","dispatchEvent","CustomEvent","bubbles","_setError","message","start","frequency","sensor","_createSensor","addEventListener","_onReading","_onError","_teardownSensor","String","stop","observe","dispose","removeEventListener","Ctor","globalThis","Accelerometer","undefined","err","WcsAccelerometer","HTMLElement","wcBindable","inputs","_core","_connectedCallbackPromise","attr","getAttribute","trim","parsed","Number","isFinite","value","removeAttribute","setAttribute","connectedCallbackPromise","connectedCallback","style","display","disconnectedCallback","bootstrapAccelerometer","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/AccelerometerCore.ts","../src/components/Accelerometer.ts","../src/bootstrapAccelerometer.ts","../src/registerComponents.ts"],"sourcesContent":["import { IConfig, IWritableConfig } from \"./types.js\";\n\ninterface IInternalConfig extends IConfig {\n tagNames: {\n accelerometer: string;\n };\n}\n\nconst _config: IInternalConfig = {\n tagNames: {\n accelerometer: \"wcs-accelerometer\",\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 { IWcBindable, WcsAccelerometerReading, WcsAccelerometerErrorDetail } from \"../types.js\";\n\nconst NULL_READING: WcsAccelerometerReading = Object.freeze({ x: null, y: null, z: null });\n\n/**\n * Headless Accelerometer primitive. A thin, framework-agnostic wrapper around\n * the Generic Sensor API's `Accelerometer` class exposed through the\n * wc-bindable protocol.\n *\n * The platform `Sensor` base class (shared by `Accelerometer` / `Gyroscope` /\n * `Magnetometer` / `AmbientLightSensor`) reports failure through an `'error'`\n * event rather than a rejected promise, so this Core can satisfy never-throw\n * (docs/async-io-node-guidelines.md §3.6) by simply forwarding that event —\n * see docs/sensor-tag-design.md §0. The one place a synchronous\n * exception *can* still escape the platform API is the `Accelerometer`\n * constructor itself (e.g. `SecurityError` on permission denial or a\n * feature-policy block); `_createSensor()` wraps that single call in\n * try/catch, mirroring FetchCore's `_doFetch` try/catch around\n * `globalThis.fetch` (packages/fetch/src/core/FetchCore.ts).\n *\n * `x`/`y`/`z` are three getters derived from the single `wcs-accelerometer:reading`\n * event (mirroring how NetworkCore exposes effectiveType/downlink/… from one\n * `wcs-network:change` event): the native `reading` event already reports all\n * three axes together, so they are not split into independent events. `reading`\n * is an event-like signal (a fresh sample every time, not a settled state) and\n * is therefore deliberately NOT same-value guarded — every sample dispatches.\n * `error` is state-like (denial / unsupported does not change from tick to\n * tick) and IS same-value guarded, and is published on its own\n * `wcs-accelerometer:error` event, independent of `reading`.\n *\n * No `_gen` generation guard: start()/stop() are a synchronous\n * subscribe/unsubscribe toggle with no asynchronous probe whose stale\n * resolution could race a dispose() — see docs/sensor-tag-design.md §1.5\n * (the same reasoning as NetworkCore, docs/network-tag-design.md §5).\n *\n * Permissions: this Core does not query `navigator.permissions` itself.\n * Compose with `<wcs-permission name=\"accelerometer\">` instead — see\n * docs/sensor-tag-design.md §\"2番目の決定: Permissions APIとの合成\".\n */\nexport class AccelerometerCore extends EventTarget {\n static wcBindable: IWcBindable = {\n protocol: \"wc-bindable\",\n version: 1,\n properties: [\n { name: \"x\", event: \"wcs-accelerometer:reading\", getter: (e: Event) => (e as CustomEvent).detail.x },\n { name: \"y\", event: \"wcs-accelerometer:reading\", getter: (e: Event) => (e as CustomEvent).detail.y },\n { name: \"z\", event: \"wcs-accelerometer:reading\", getter: (e: Event) => (e as CustomEvent).detail.z },\n { name: \"error\", event: \"wcs-accelerometer:error\" },\n ],\n commands: [{ name: \"start\" }, { name: \"stop\" }],\n };\n\n private _target: EventTarget;\n private _reading: WcsAccelerometerReading = NULL_READING;\n private _error: WcsAccelerometerErrorDetail | null = null;\n\n // The live sensor instance while started (null otherwise), kept so stop()\n // can remove its listeners precisely and so start() can detect \"already\n // started\" without a separate boolean (docs/async-io-node-guidelines.md §3.5\n // idempotency).\n private _sensor: (EventTarget & { start(): void; stop(): void }) | null = null;\n\n constructor(target?: EventTarget) {\n super();\n this._target = target ?? this;\n }\n\n get x(): number | null {\n return this._reading.x;\n }\n\n get y(): number | null {\n return this._reading.y;\n }\n\n get z(): number | null {\n return this._reading.z;\n }\n\n get error(): WcsAccelerometerErrorDetail | null {\n return this._error;\n }\n\n /** No asynchronous probe to await: start()/stop() are synchronous\n * (docs/async-io-node-guidelines.md §3.8 is satisfied trivially, mirroring\n * NetworkCore). */\n get ready(): Promise<void> {\n return Promise.resolve();\n }\n\n // --- State setters ---\n\n // Deliberately NOT same-value guarded: a `reading` is a fresh sample, not a\n // settled state, so it must dispatch every time even when the values happen\n // to repeat (docs/sensor-tag-design.md §1.1).\n private _setReading(reading: WcsAccelerometerReading): void {\n this._reading = reading;\n this._target.dispatchEvent(new CustomEvent(\"wcs-accelerometer:reading\", {\n detail: reading,\n bubbles: true,\n }));\n }\n\n private _setError(error: WcsAccelerometerErrorDetail | null): void {\n // Same-value guard (by error name + message): error is state-like, unlike\n // reading — a repeated identical error (same name and message) must not\n // redispatch.\n if (this._error?.error === error?.error && this._error?.message === error?.message) return;\n this._error = error;\n this._target.dispatchEvent(new CustomEvent(\"wcs-accelerometer:error\", {\n detail: error,\n bubbles: true,\n }));\n }\n\n // --- Public API ---\n\n /**\n * Start the sensor at the given `frequency` (Hz), or the platform default\n * when omitted. Idempotent while already started: a redundant start() does\n * not construct a second sensor instance (which would leak the first).\n * Restart with a different frequency via stop() + start().\n *\n * Synchronous, mirroring the native `Sensor.start()` — never throws\n * (docs/async-io-node-guidelines.md §3.6): both \"unsupported\" and a\n * synchronous constructor exception (permission denial, feature-policy\n * block) are converted to the `error` property instead of propagating.\n */\n start(frequency?: number): void {\n if (this._sensor) return;\n const sensor = this._createSensor(frequency);\n if (!sensor) return;\n sensor.addEventListener(\"reading\", this._onReading as EventListener);\n sensor.addEventListener(\"error\", this._onError as EventListener);\n this._sensor = sensor;\n try {\n sensor.start();\n } catch (e: any) {\n // Defensive: the platform contract says start()/stop() do not throw\n // (failures surface via the 'error' event), but never-throw is a hard\n // requirement here, so guard against a non-conformant implementation\n // too.\n this._teardownSensor();\n this._setError({ error: e?.name ?? \"error\", message: e?.message ?? String(e) });\n }\n }\n\n /** Stop the sensor and detach its listeners. Safe to call when not started. */\n stop(): void {\n if (!this._sensor) return;\n try {\n this._sensor.stop();\n } catch {\n // Never-throw defensive guard, symmetric with start(). Teardown below\n // still runs so listeners are detached regardless.\n }\n this._teardownSensor();\n }\n\n /** Lifecycle alias for start(), so the Shell's connectedCallback can drive\n * this Core the same way as other IO nodes' observe()/dispose() pair. No\n * asynchronous probe, so the returned promise always resolves immediately. */\n observe(frequency?: number): Promise<void> {\n this.start(frequency);\n return this.ready;\n }\n\n /** Lifecycle alias for stop(), invoked from the Shell's disconnectedCallback. */\n dispose(): void {\n this.stop();\n }\n\n // --- Internal ---\n\n // Both call sites (start()'s catch, stop()) only ever invoke this once\n // `this._sensor` is already known non-null, so there is no null-guard here\n // (nothing to defend against).\n private _teardownSensor(): void {\n this._sensor!.removeEventListener(\"reading\", this._onReading as EventListener);\n this._sensor!.removeEventListener(\"error\", this._onError as EventListener);\n this._sensor = null;\n }\n\n /**\n * Construct the platform `Accelerometer`, guarding both non-support and a\n * synchronous constructor exception. Never calls the raw `new Accelerometer(...)`\n * anywhere else in this class — see docs/sensor-tag-design.md §1.5.\n *\n * API resolution is call-time (docs/async-io-node-guidelines.md §3.7):\n * re-checked on every start(), never cached, so tests can install/remove the\n * global freely and an unsupported environment is always reported correctly.\n */\n private _createSensor(frequency?: number): (EventTarget & { start(): void; stop(): void }) | null {\n const Ctor = (globalThis as any).Accelerometer;\n if (typeof Ctor !== \"function\") {\n this._setError({ error: \"unsupported\", message: \"Accelerometer is not supported\" });\n return null;\n }\n try {\n return new Ctor(frequency !== undefined ? { frequency } : undefined);\n } catch (e: any) {\n // SecurityError (permission denial, feature-policy block) or any other\n // synchronous construction failure. Mirrors the FetchCore._doFetch\n // try/catch structure (packages/fetch/src/core/FetchCore.ts) — a\n // synchronous constructor call here instead of an awaited fetch().\n this._setError({ error: e?.name ?? \"error\", message: e?.message ?? String(e) });\n return null;\n }\n }\n\n private _onReading = (event: Event): void => {\n const sensor = event.target as unknown as { x: number | null; y: number | null; z: number | null };\n this._setReading({ x: sensor.x, y: sensor.y, z: sensor.z });\n };\n\n private _onError = (event: Event): void => {\n const err = (event as any).error as { name?: string; message?: string } | undefined;\n // Fallback is a meaningful constant, NOT String(err): a SensorErrorEvent\n // without an `error` field would otherwise stringify `undefined` into the\n // literal message \"undefined\" (aligned across the sensor family).\n this._setError({ error: err?.name ?? \"error\", message: err?.message ?? \"Sensor error\" });\n };\n}\n","import { IWcBindable, WcsAccelerometerErrorDetail } from \"../types.js\";\nimport { AccelerometerCore } from \"../core/AccelerometerCore.js\";\n\n/**\n * `<wcs-accelerometer>` — declarative Generic Sensor API (`Accelerometer`)\n * monitor + start/stop control.\n *\n * Unlike `<wcs-network>` / `<wcs-permission>` (pure monitors), this Shell is a\n * bidirectional node: `start`/`stop` commands (command-token: state → element)\n * alongside the `x`/`y`/`z`/`error` observable surface (event-token: element →\n * state). The `frequency` attribute is the sole configuration input, forwarded\n * to the platform `Accelerometer` constructor's `{ frequency }` option\n * (docs/sensor-tag-design.md §1.2). The getter normalizes it: a non-finite or\n * non-positive value (NaN, 0, negative) reads back as `null` — meaning \"no\n * frequency specified\" — so start() falls back to the platform default rather\n * than forwarding a value the sensor would reject. Any positive finite value is\n * passed through verbatim (no upper-bound clamping — an out-of-range-but-positive\n * rate is still left to the browser/sensor to reject via `error`).\n *\n * Permission handling is intentionally NOT implemented here. Compose with\n * `<wcs-permission name=\"accelerometer\">` instead (see the README's permission\n * example, \"Gate on permission, then start\", and docs/sensor-tag-design.md).\n */\nexport class WcsAccelerometer extends HTMLElement {\n static hasConnectedCallbackPromise = true;\n\n static wcBindable: IWcBindable = {\n ...AccelerometerCore.wcBindable,\n inputs: [{ name: \"frequency\" }],\n // Core の commands をそのまま継承(単一情報源)。\n commands: AccelerometerCore.wcBindable.commands,\n };\n\n private _core: AccelerometerCore;\n private _connectedCallbackPromise: Promise<void> = Promise.resolve();\n private _internals: ElementInternals | null = null;\n\n constructor() {\n super();\n this._core = new AccelerometerCore(this);\n this._internals = this._initInternals();\n this._wireStates({\n \"wcs-accelerometer: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/async-io-node-guidelines.md §3.6): attachInternals is\n // 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 * Sampling frequency in Hz. Reads back `null` when unset, blank, or when the\n * attribute does not parse to a positive finite number (NaN, `\"0\"`, negative)\n * — in every such \"no usable value\" case the platform default applies.\n *\n * Note the deliberate set/get asymmetry: `set frequency(0)` (or any\n * non-positive/non-finite value) still writes the attribute verbatim for\n * transparency/inspectability, but the getter normalizes it back to `null`.\n * A round-trip through a non-positive value therefore does NOT preserve it —\n * that value carries no valid sampling meaning, so it is treated as \"unset\"\n * on read. Only positive finite frequencies survive a set→get round-trip.\n */\n get frequency(): number | null {\n const attr = this.getAttribute(\"frequency\");\n if (attr === null || attr.trim() === \"\") return null;\n const parsed = Number(attr);\n return Number.isFinite(parsed) && parsed > 0 ? parsed : null;\n }\n\n set frequency(value: number | null | undefined) {\n if (value === null || value === undefined) {\n this.removeAttribute(\"frequency\");\n } else {\n this.setAttribute(\"frequency\", String(value));\n }\n }\n\n // --- Core delegated getters ---\n\n get x(): number | null {\n return this._core.x;\n }\n\n get y(): number | null {\n return this._core.y;\n }\n\n get z(): number | null {\n return this._core.z;\n }\n\n get error(): WcsAccelerometerErrorDetail | null {\n return this._core.error;\n }\n\n get connectedCallbackPromise(): Promise<void> {\n return this._connectedCallbackPromise;\n }\n\n // --- Commands ---\n\n start(): void {\n this._core.start(this.frequency ?? undefined);\n }\n\n stop(): void {\n this._core.stop();\n }\n\n // --- Lifecycle ---\n\n // Deliberately does NOT auto-start the sensor on connect. Unlike\n // Geolocation (whose default phase acquires a fix immediately unless\n // `manual` is set), Accelerometer has no such \"connect implies observing\"\n // precedent in the design doc (docs/sensor-tag-design.md §1.3):\n // start/stop are the only commands, so connecting the element merely makes\n // it inert until a command-token `start` (or the `start()` method) is\n // invoked. This also keeps behavior predictable when composed with\n // `<wcs-permission name=\"accelerometer\">`: the caller decides when to start,\n // typically gated on `granted`.\n connectedCallback(): void {\n this.style.display = \"none\";\n // No asynchronous probe to await (docs/async-io-node-guidelines.md §3.8);\n // kept for SSR uniformity with other IO nodes.\n this._connectedCallbackPromise = this._core.ready;\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 bootstrapAccelerometer(userConfig?: IWritableConfig): void {\n if (userConfig) {\n setConfig(userConfig);\n }\n registerComponents();\n}\n","import { WcsAccelerometer } from \"./components/Accelerometer.js\";\nimport { config } from \"./config.js\";\n\nexport function registerComponents(): void {\n if (!customElements.get(config.tagNames.accelerometer)) {\n customElements.define(config.tagNames.accelerometer, WcsAccelerometer);\n }\n}\n"],"names":["_config","tagNames","accelerometer","deepFreeze","obj","Object","freeze","key","keys","deepClone","clone","frozenConfig","config","getConfig","NULL_READING","x","y","z","AccelerometerCore","EventTarget","static","protocol","version","properties","name","event","getter","e","detail","commands","_target","_reading","_error","_sensor","constructor","target","super","this","error","ready","Promise","resolve","_setReading","reading","dispatchEvent","CustomEvent","bubbles","_setError","message","start","frequency","sensor","_createSensor","addEventListener","_onReading","_onError","_teardownSensor","String","stop","observe","dispose","removeEventListener","Ctor","globalThis","Accelerometer","undefined","err","WcsAccelerometer","HTMLElement","wcBindable","inputs","_core","_connectedCallbackPromise","_internals","_initInternals","_wireStates","d","debugStates","states","attachInternals","internals","add","delete","map","toStates","entries","debug","hasAttribute","on","toggleAttribute","attr","getAttribute","trim","parsed","Number","isFinite","value","removeAttribute","setAttribute","connectedCallbackPromise","connectedCallback","style","display","disconnectedCallback","bootstrapAccelerometer","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/accelerometer",
3
- "version": "1.16.0",
3
+ "version": "1.17.0",
4
4
  "description": "Declarative Accelerometer component for Web Components. Framework-agnostic Generic Sensor API (Accelerometer) monitor via wc-bindable-protocol.",
5
5
  "type": "module",
6
6
  "main": "./dist/index.esm.js",