@wcstack/camera 4.0.0-rc.8 → 4.0.0-rc.9

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/dist/index.esm.js CHANGED
@@ -702,6 +702,61 @@ function upgradeProperties(element) {
702
702
  }
703
703
  }
704
704
 
705
+ // ===========================================================================
706
+ // AUTO-GENERATED FILE - DO NOT EDIT.
707
+ // Generated from /protocol/input-attribute.ts by scripts/sync-protocol-types.mjs.
708
+ // Run `node scripts/sync-protocol-types.mjs` after editing the source.
709
+ // ===========================================================================
710
+ // 属性へ反映する wc-bindable 入力の producer 側(SPEC-extensions § Producer guidance for inputs の P1〜P3)。
711
+ // 入力の setter は属性をこの 2 関数で書く。それで次が揃う:
712
+ // - `undefined` は「値が無い」(P1): 属性を、この関数で最初に書く前の状態 — マークアップに書かれた値、
713
+ // 無ければ属性なし(= その入力の文書化した既定値)— へ戻す。applier プロファイルを宣言する binder は
714
+ // 値の後の `undefined` を書き(A2)、React 19 も書き、直接の代入でも届く。
715
+ // - `null` はクリア(P2): 属性なし、つまり文書化した既定値。
716
+ // - どちらも文字列 "undefined" / "null" として属性に入らない。
717
+ //
718
+ // 「最初に書く前」は、その最初の書き込みのときに読む(遅延)。upgrade 前に代入されたプロパティは
719
+ // connectedCallback の upgradeProperties() が通し直すので、そのときにはパーサが書いた属性が揃っている。
720
+ // 要素自身が setter を通さずに書いた属性は、最初の書き込みより前なら「最初の状態」に含まれる。
721
+ //
722
+ // SINGLE SOURCE OF TRUTH: edit only this file (/protocol/input-attribute.ts), then run
723
+ // `node scripts/sync-protocol-types.mjs` to regenerate the per-package copies
724
+ // (packages/<pkg>/src/protocol/inputAttribute.ts). Those copies are generated — do not edit them.
725
+ const initialAttributes = new WeakMap();
726
+ /** The attribute as it stood before the first write through these helpers. */
727
+ function initialAttribute(el, name) {
728
+ let byName = initialAttributes.get(el);
729
+ if (byName === undefined) {
730
+ byName = new Map();
731
+ initialAttributes.set(el, byName);
732
+ }
733
+ if (!byName.has(name))
734
+ byName.set(name, el.getAttribute(name));
735
+ return byName.get(name);
736
+ }
737
+ function writeAttribute(el, name, value) {
738
+ if (value === null)
739
+ el.removeAttribute(name);
740
+ else
741
+ el.setAttribute(name, value);
742
+ }
743
+ /**
744
+ * A value attribute. `value` is written as `String(value)`; `null` removes the attribute;
745
+ * `undefined` restores the attribute the element started with.
746
+ */
747
+ function reflectAttribute(el, name, value) {
748
+ const initial = initialAttribute(el, name);
749
+ writeAttribute(el, name, value === undefined ? initial : value === null ? null : String(value));
750
+ }
751
+ /**
752
+ * A boolean attribute, present while `value` is truthy (`null` and `false` remove it);
753
+ * `undefined` restores the attribute the element started with.
754
+ */
755
+ function reflectBooleanAttribute(el, name, value) {
756
+ const initial = initialAttribute(el, name);
757
+ writeAttribute(el, name, value === undefined ? initial : value ? "" : null);
758
+ }
759
+
705
760
  /**
706
761
  * `<wcs-camera>` — declarative camera capture with a built-in preview.
707
762
  *
@@ -825,22 +880,33 @@ class WcsCamera extends HTMLElement {
825
880
  }
826
881
  }
827
882
  // --- Attribute accessors ---
883
+ //
884
+ // The setters never let setAttribute stringify null / undefined (a "undefined"
885
+ // device-id would become an exact constraint no camera matches): `null`
886
+ // removes the attribute (the default), `undefined` restores the attribute the
887
+ // element started with (wc-bindable producer guidance P1; React 19 and a
888
+ // direct assignment deliver it, @wcstack/state does not).
828
889
  get audio() { return this.hasAttribute("audio"); }
829
- set audio(value) { this._toggleAttr("audio", value); }
890
+ set audio(value) { reflectBooleanAttribute(this, "audio", value); }
830
891
  get facingMode() {
831
892
  return this.getAttribute("facing-mode") === "environment" ? "environment" : "user";
832
893
  }
833
- set facingMode(value) { this.setAttribute("facing-mode", value); }
834
- get deviceId() { return this.getAttribute("device-id") ?? ""; }
835
- set deviceId(value) { this.setAttribute("device-id", value); }
894
+ set facingMode(value) { reflectAttribute(this, "facing-mode", value); }
895
+ // `deviceId` is an input (the `device-id` request) and an output (the device the
896
+ // stream uses, published with `wcs-camera:device-changed`). Reading it gives the
897
+ // device in use once one is known — what the event carries, and what a binder's
898
+ // initial sync reads — and the request until then. The constraints read the
899
+ // request from the attribute (`_constraints`), as <wcs-recorder>'s mimeType does.
900
+ get deviceId() { return this._core.deviceId ?? this.getAttribute("device-id") ?? ""; }
901
+ set deviceId(value) { reflectAttribute(this, "device-id", value); }
836
902
  get width() { return this._numberAttr("width"); }
837
- set width(value) { this.setAttribute("width", String(value)); }
903
+ set width(value) { reflectAttribute(this, "width", value); }
838
904
  get height() { return this._numberAttr("height"); }
839
- set height(value) { this.setAttribute("height", String(value)); }
905
+ set height(value) { reflectAttribute(this, "height", value); }
840
906
  get autostart() { return this.hasAttribute("autostart"); }
841
- set autostart(value) { this._toggleAttr("autostart", value); }
907
+ set autostart(value) { reflectBooleanAttribute(this, "autostart", value); }
842
908
  get keepAlive() { return this.hasAttribute("keep-alive"); }
843
- set keepAlive(value) { this._toggleAttr("keep-alive", value); }
909
+ set keepAlive(value) { reflectBooleanAttribute(this, "keep-alive", value); }
844
910
  /** The internal preview `<video>` (for advanced styling/measurement). */
845
911
  get videoElement() { return this._video; }
846
912
  // --- Core delegated getters ---
@@ -884,14 +950,6 @@ class WcsCamera extends HTMLElement {
884
950
  }
885
951
  }
886
952
  // --- Internal ---
887
- _toggleAttr(name, value) {
888
- if (value) {
889
- this.setAttribute(name, "");
890
- }
891
- else {
892
- this.removeAttribute(name);
893
- }
894
- }
895
953
  _numberAttr(name) {
896
954
  const attr = this.getAttribute(name);
897
955
  if (attr === null || attr.trim() === "")
@@ -901,8 +959,11 @@ class WcsCamera extends HTMLElement {
901
959
  }
902
960
  _constraints() {
903
961
  const c = { audio: this.audio, facingMode: this.facingMode };
904
- if (this.deviceId)
905
- c.deviceId = this.deviceId;
962
+ // the request, not `get deviceId()` (the device in use): after switchCamera()
963
+ // removed it, the previous device must not stay pinned
964
+ const requested = this.getAttribute("device-id");
965
+ if (requested)
966
+ c.deviceId = requested;
906
967
  if (Number.isFinite(this.width))
907
968
  c.width = this.width;
908
969
  if (Number.isFinite(this.height))
@@ -1398,14 +1459,20 @@ class WcsRecorder extends HTMLElement {
1398
1459
  // browser may pick a different type, or fill one in when none was requested, and
1399
1460
  // bindings must read the actual value. The input side is read straight from the
1400
1461
  // attribute in `_options()`. The setter still writes the request attribute.
1462
+ //
1463
+ // The setters never let setAttribute stringify null / undefined (a "undefined"
1464
+ // mime-type would be requested from MediaRecorder): `null` removes the
1465
+ // attribute (no request — the browser's default), `undefined` restores the
1466
+ // attribute the element started with (wc-bindable producer guidance P1;
1467
+ // React 19 and a direct assignment deliver it, @wcstack/state does not).
1401
1468
  get mimeType() { return this._core.mimeType; }
1402
- set mimeType(value) { this.setAttribute("mime-type", value); }
1469
+ set mimeType(value) { reflectAttribute(this, "mime-type", value); }
1403
1470
  get timeslice() { return this._numberAttr("timeslice"); }
1404
- set timeslice(value) { this.setAttribute("timeslice", String(value)); }
1471
+ set timeslice(value) { reflectAttribute(this, "timeslice", value); }
1405
1472
  get audioBitsPerSecond() { return this._numberAttr("audio-bits"); }
1406
- set audioBitsPerSecond(value) { this.setAttribute("audio-bits", String(value)); }
1473
+ set audioBitsPerSecond(value) { reflectAttribute(this, "audio-bits", value); }
1407
1474
  get videoBitsPerSecond() { return this._numberAttr("video-bits"); }
1408
- set videoBitsPerSecond(value) { this.setAttribute("video-bits", String(value)); }
1475
+ set videoBitsPerSecond(value) { reflectAttribute(this, "video-bits", value); }
1409
1476
  // --- Core delegated getters ---
1410
1477
  get recording() { return this._core.recording; }
1411
1478
  get paused() { return this._core.paused; }