@wcstack/picture-in-picture 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
@@ -159,6 +159,55 @@ Fullscreen の `fullscreenchange`(`document` に発火)と異なり、Pictur
159
159
 
160
160
  これにより、複数の `<wcs-pip>` インスタンスは自然に自己フィルタされます。各インスタンスは自分の `<video>` target のイベントのみを受け取るため、あるインスタンスが Picture-in-Picture に入っても他のインスタンスの `active` が誤って `true` になることはありません(`docs/picture-in-picture-tag-design.md` §5 参照)。
161
161
 
162
+ ## `:state()` による CSS スタイリング
163
+
164
+ `<wcs-pip>` は 1 つの boolean 出力ステートを
165
+ [`ElementInternals` の `CustomStateSet`](https://developer.mozilla.org/ja/docs/Web/API/CustomStateSet)
166
+ に反映します。そのため `data-wcs` バインディングやクラスの手動トグルなしに、CSS の
167
+ `:state()` 疑似クラスで直接スタイリングできます。
168
+
169
+ | ステート | on になる条件 |
170
+ |----------|----------------|
171
+ | `active` | `wcs-pip:change` が `detail.active === true` で発火(`false` で発火するとクリア) |
172
+
173
+ ```css
174
+ wcs-pip:state(active) ~ .back-to-page-button { display: inline-block; }
175
+ wcs-pip:state(active) ~ .back-to-page-button { display: none; } /* デフォルト */
176
+ ```
177
+
178
+ 属性やクラスと異なり `:state()` は要素の外部から書き込めないため、この出力ステートが
179
+ 入力と混同される心配がありません。`error` はあえて反映していません — 専用イベントを
180
+ 持たないため(上記「出力 state」参照)、ステートの切り替えを導出する材料がありません。
181
+
182
+ **対応ブラウザ**(新構文 `:state(x)`): Chrome/Edge 125+、Safari 17.4+、Firefox 126+。
183
+ 非対応の環境ではステートが一切 set されないだけです — `:state()` セレクタがマッチしなく
184
+ なりますが、`<wcs-pip>` 自体は通常どおり動作し続けます(graceful degradation・never-throw)。
185
+
186
+ **SSR:** `:state()` は HTML にシリアライズできないため、サーバーレンダリングされた
187
+ マークアップの初期ペイントにはこのステートは乗りません(`@wcstack/server` は無改変)。
188
+ ハイドレーション前の見た目を制御したい場合は、代わりに `wcs-pip:not(:defined)` と組み合わせてください。
189
+
190
+ ### デバッグ
191
+
192
+ カスタムステートは DevTools の Elements パネルには表示されず、`attachInternals()`
193
+ は同一要素に 2 回呼べないため、コンソールから直接覗く手段がありません。そのための
194
+ デバッグ専用の補助を 2 つ用意しています:
195
+
196
+ - `el.debugStates` — 現在 on になっているステート名の**スナップショット**配列
197
+ (例: `["active"]`)。`wc-bindable` の一部ではなく(バインド対象ではない)、
198
+ 形状も契約として保証されません — デバッグ用途にのみ使ってください。
199
+ - `debug-states` 属性(opt-in・既定 OFF)は、ステート変化を要素の
200
+ `data-wcs-state-active` 属性にミラーします。Elements パネルを開いておけば、
201
+ トグルのたびにハイライトされます:
202
+
203
+ ```html
204
+ <wcs-pip target="#player" debug-states></wcs-pip>
205
+ ```
206
+
207
+ **CSS は `data-wcs-state-*` ではなく `:state()` に書いてください。** ミラーされた
208
+ 属性は、DevTools を開いた状態でステート変化を可視化するためだけのものであり、
209
+ スタイリング用の正式なフックではありません。
210
+
162
211
  ## Binding Contract(`wcBindable`)
163
212
 
164
213
  Core と Shell の両方が [wc-bindable](https://github.com/csbc-dev) プロトコルを宣言します。
package/README.md CHANGED
@@ -159,6 +159,58 @@ Unlike Fullscreen's `fullscreenchange` (which fires on `document`), Picture-in-P
159
159
 
160
160
  This also means multiple `<wcs-pip>` instances naturally self-filter: each instance only hears events from its own `<video>` target, so one instance entering Picture-in-Picture never flips another instance's `active` to `true` (see `docs/picture-in-picture-tag-design.md` §5).
161
161
 
162
+ ## CSS styling with `:state()`
163
+
164
+ `<wcs-pip>` reflects one boolean output state onto its
165
+ [`ElementInternals` `CustomStateSet`](https://developer.mozilla.org/en-US/docs/Web/API/CustomStateSet),
166
+ so you can style it directly from CSS with the `:state()` pseudo-class — no
167
+ `data-wcs` binding or extra class toggling required.
168
+
169
+ | State | On when |
170
+ |-------|---------|
171
+ | `active` | `wcs-pip:change` fires with `detail.active === true` (cleared when it fires with `false`) |
172
+
173
+ ```css
174
+ wcs-pip:state(active) ~ .back-to-page-button { display: inline-block; }
175
+ wcs-pip:state(active) ~ .back-to-page-button { display: none; } /* default */
176
+ ```
177
+
178
+ Unlike attributes or classes, `:state()` cannot be written from outside the
179
+ element, so there is no risk of confusing this output state with an input.
180
+ `error` is intentionally **not** reflected — it has no dedicated event (see
181
+ "Output state" above), so there is nothing to derive a state toggle from.
182
+
183
+ **Browser support** (`:state(x)` syntax): Chrome/Edge 125+, Safari 17.4+,
184
+ Firefox 126+. In older browsers the states are simply never set — `:state()`
185
+ selectors never match, but `<wcs-pip>` itself keeps working normally
186
+ (graceful degradation, never-throw).
187
+
188
+ **SSR**: `:state()` cannot be serialized into HTML, so server-rendered markup
189
+ never carries these states on first paint (`@wcstack/server` is unaffected).
190
+ If you need to style the pre-hydration gap, pair your rule with
191
+ `wcs-pip:not(:defined)` instead.
192
+
193
+ ### Debugging
194
+
195
+ Custom states are invisible in DevTools' Elements panel and `attachInternals()`
196
+ cannot be called twice, so there is no console way to inspect them directly.
197
+ Two debug-only aids are provided for that:
198
+
199
+ - `el.debugStates` — a **snapshot** array of the currently-on state names
200
+ (e.g. `["active"]`). It is not part of `wc-bindable` (not a bind target)
201
+ and its shape is not a guaranteed contract — use it for debugging only.
202
+ - The `debug-states` attribute (opt-in, default off) mirrors state changes
203
+ onto a `data-wcs-state-active` attribute on the element, so the Elements
204
+ panel highlights it as it toggles:
205
+
206
+ ```html
207
+ <wcs-pip target="#player" debug-states></wcs-pip>
208
+ ```
209
+
210
+ **Write your CSS against `:state()`, not `data-wcs-state-*`.** The mirrored
211
+ attribute exists purely to make state changes visible while debugging with
212
+ DevTools open; it is not a supported styling hook.
213
+
162
214
  ## Binding Contract (`wcBindable`)
163
215
 
164
216
  Both the Core and the Shell declare the [wc-bindable](https://github.com/csbc-dev) protocol.
package/dist/index.d.ts CHANGED
@@ -158,7 +158,11 @@ declare class WcsPip extends HTMLElement {
158
158
  static wcBindable: IWcBindable;
159
159
  private _core;
160
160
  private _connectedCallbackPromise;
161
+ private _internals;
161
162
  constructor();
163
+ get debugStates(): string[];
164
+ private _initInternals;
165
+ private _wireStates;
162
166
  get connectedCallbackPromise(): Promise<void>;
163
167
  get target(): string;
164
168
  set target(value: string);
package/dist/index.esm.js CHANGED
@@ -282,9 +282,62 @@ class WcsPip extends HTMLElement {
282
282
  };
283
283
  _core;
284
284
  _connectedCallbackPromise = Promise.resolve();
285
+ _internals = null;
285
286
  constructor() {
286
287
  super();
287
288
  this._core = new PipCore(this);
289
+ this._internals = this._initInternals();
290
+ this._wireStates({
291
+ "wcs-pip:change": (d) => ({ active: d?.active === true }),
292
+ });
293
+ }
294
+ // CSS state reflection (:state()) — debug-only snapshot getter. NOT part of
295
+ // wc-bindable (not a bind target); see README "CSS styling with :state()".
296
+ // MUST NOT return the live CustomStateSet (that would let callers write
297
+ // states from outside, defeating the point of :state() being read-only).
298
+ get debugStates() {
299
+ return this._internals ? [...this._internals.states] : [];
300
+ }
301
+ _initInternals() {
302
+ // never-throw (docs/custom-state-reflection-design.md §3.1): attachInternals
303
+ // is absent in happy-dom / older environments, and pre-125 Chromium rejects
304
+ // non-dashed state names from states.add() (probed and discarded here).
305
+ // Either case silently disables reflection — the component still works,
306
+ // it just doesn't expose :state() selectors.
307
+ try {
308
+ if (typeof this.attachInternals !== "function")
309
+ return null;
310
+ const internals = this.attachInternals();
311
+ internals.states.add("wcs-probe");
312
+ internals.states.delete("wcs-probe");
313
+ return internals;
314
+ }
315
+ catch {
316
+ return null;
317
+ }
318
+ }
319
+ _wireStates(map) {
320
+ if (this._internals === null)
321
+ return;
322
+ const states = this._internals.states;
323
+ for (const [event, toStates] of Object.entries(map)) {
324
+ this.addEventListener(event, (e) => {
325
+ const debug = this.hasAttribute("debug-states");
326
+ for (const [name, on] of Object.entries(toStates(e.detail))) {
327
+ try {
328
+ if (on) {
329
+ states.add(name);
330
+ }
331
+ else {
332
+ states.delete(name);
333
+ }
334
+ }
335
+ catch { /* never-throw */ }
336
+ if (debug)
337
+ this.toggleAttribute(`data-wcs-state-${name}`, on);
338
+ }
339
+ });
340
+ }
288
341
  }
289
342
  get connectedCallbackPromise() {
290
343
  return this._connectedCallbackPromise;
@@ -1 +1 @@
1
- {"version":3,"file":"index.esm.js","sources":["../src/config.ts","../src/core/PipCore.ts","../src/components/Pip.ts","../src/registerComponents.ts","../src/bootstrapPip.ts"],"sourcesContent":["import { IConfig, IWritableConfig } from \"./types.js\";\n\ninterface IInternalConfig extends IConfig {\n tagNames: {\n pip: string;\n };\n}\n\nconst _config: IInternalConfig = {\n tagNames: {\n pip: \"wcs-pip\",\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 } from \"../types.js\";\n\n/**\n * Headless Picture-in-Picture primitive. A thin, framework-agnostic wrapper\n * around the classic Picture-in-Picture API\n * (`HTMLVideoElement.requestPictureInPicture()` / `document.exitPictureInPicture()` /\n * `document.pictureInPictureElement`) exposed through the wc-bindable protocol.\n *\n * This Core follows the same basic pattern as `@wcstack/fullscreen`'s\n * `FullscreenCore` (docs/fullscreen-tag-design.md): target resolution is done\n * by the Shell (this Core receives the resolved element at call time), API\n * resolution is call-time/non-cached, `_gen` is a single Core-level generation\n * guard, and `error` is a simple single field (no permission-style 4-value\n * state). See docs/picture-in-picture-tag-design.md for the differences from\n * Fullscreen:\n *\n * - **§2 target constraint**: the resolved target MUST be a `<video>` element.\n * Picture-in-Picture is only defined as an instance method of\n * `HTMLVideoElement` — unlike Fullscreen, which any `Element` supports. A\n * non-`<video>` target is a never-throw failure: it is treated the same as\n * an unresolved target and reported via `error`.\n * - **§3 event subscription target**: `enterpictureinpicture` /\n * `leavepictureinpicture` fire on the `<video>` element itself, not on\n * `document` (the reverse of Fullscreen's `document`-level\n * `fullscreenchange`). The Core attaches/detaches these listeners directly\n * on the resolved `<video>` element, re-wiring them whenever the target is\n * re-resolved (e.g. the Shell's `target` attribute changes).\n */\nexport class PipCore extends EventTarget {\n static wcBindable: IWcBindable = {\n protocol: \"wc-bindable\",\n version: 1,\n properties: [\n { name: \"active\", event: \"wcs-pip:change\", getter: (e: Event) => (e as CustomEvent).detail.active },\n ],\n commands: [\n { name: \"requestPictureInPicture\", async: true },\n { name: \"exitPictureInPicture\", async: true },\n ],\n };\n\n private _target: EventTarget;\n private _active: boolean = false;\n private _error: any = null;\n\n // The <video> element the Core currently subscribes to for\n // enterpictureinpicture/leavepictureinpicture (null when unresolved/torn down).\n private _video: HTMLVideoElement | null = null;\n\n // Generation guard (§3.4 / fullscreen-tag-design.md §6): bumped on dispose()\n // and each async command start. A completion that lands after dispose() (or\n // after a superseding call) is stale and MUST NOT write state.\n private _gen = 0;\n\n // SSR (§3.8): no asynchronous probe to await, so readiness is immediate.\n private _ready: Promise<void> = Promise.resolve();\n\n constructor(target?: EventTarget) {\n super();\n this._target = target ?? this;\n }\n\n get ready(): Promise<void> {\n return this._ready;\n }\n\n get active(): boolean {\n return this._active;\n }\n\n get error(): any {\n return this._error;\n }\n\n // --- Lifecycle (§3.5) ---\n\n /**\n * (Re-)subscribe to `enterpictureinpicture`/`leavepictureinpicture` on\n * `element` (the Shell's resolved `<video>` target). Idempotent when called\n * again with the same element; re-wires the listeners when the element\n * changes (e.g. the `target` attribute was changed), detaching from the\n * previous element first so no stale listener lingers.\n */\n observe(element: HTMLVideoElement | null): Promise<void> {\n if (this._video === element) {\n return this._ready;\n }\n this._detach();\n this._video = element;\n if (element) {\n element.addEventListener(\"enterpictureinpicture\", this._onEnter);\n element.addEventListener(\"leavepictureinpicture\", this._onLeave);\n }\n this._syncActive();\n return this._ready;\n }\n\n dispose(): void {\n this._gen++;\n this._detach();\n this._video = null;\n }\n\n // --- Commands (§3.6 never-throw) ---\n\n /**\n * Request Picture-in-Picture for `element`. `element` must be a `<video>`\n * (checked before the gesture-context failure path, since a type mismatch is\n * an environment-independent, permanent error — docs/picture-in-picture-tag-design.md §2).\n * Never throws: all failures (wrong tag, unsupported API, gesture-context\n * rejection) are funneled into `error` and the returned promise resolves.\n */\n async requestPictureInPicture(element: HTMLVideoElement | null): Promise<void> {\n const gen = ++this._gen;\n if (!element || element.tagName !== \"VIDEO\") {\n this._setError({ message: \"target must be a <video> element.\" });\n return;\n }\n // Re-wire to `element` before issuing the platform call: a caller may\n // request a <video> different from the one last passed to observe() (e.g.\n // the Shell's target attribute pointed at nothing at connect time and the\n // matching <video> was only inserted later, so no attributeChangedCallback\n // ever re-resolved it). Without this, `_video` stays stale and\n // `_syncActive()` below (and future enter/leave events) would never\n // recognize `element` as this Core's target, leaving `active` permanently\n // wrong even though the request succeeded (mirrors\n // FullscreenCore.requestFullscreen()'s unconditional `this._resolvedTarget\n // = element` assignment — docs/fullscreen-tag-design.md §6).\n this.observe(element);\n const fn = this._requestPictureInPictureFn(element);\n if (!fn) {\n this._setError({ message: \"Picture-in-Picture API is not supported.\" });\n return;\n }\n try {\n await fn.call(element);\n if (gen !== this._gen) return; // stale\n this._setError(null);\n this._syncActive(); // belt-and-suspenders (mirrors FullscreenCore's _applyActive() on success)\n } catch (e: any) {\n if (gen !== this._gen) return; // stale\n this._setError(e); // e.g. NotAllowedError (gesture-context rejection)\n }\n }\n\n /**\n * Exit Picture-in-Picture. Mirrors FullscreenCore.exitFullscreen(): a\n * silent no-op (resolve, no error) when nothing is currently in\n * Picture-in-Picture — see fullscreen-tag-design.md §7.\n */\n async exitPictureInPicture(): Promise<void> {\n // no-op checks come BEFORE the generation bump: a call that does nothing\n // must not supersede an in-flight requestPictureInPicture() — bumping\n // first would make the pending request's settle handling stale and\n // silently swallow its error update (mirrors\n // FullscreenCore.exitFullscreen()).\n if (this._pictureInPictureElement() === null) return; // already not in PiP: silent no-op\n const fn = this._exitPictureInPictureFn();\n if (!fn) return; // unsupported: silent no-op (semantically already \"not in PiP\")\n const gen = ++this._gen;\n try {\n await fn();\n if (gen !== this._gen) return;\n this._setError(null);\n this._syncActive(); // belt-and-suspenders (mirrors FullscreenCore.exitFullscreen()'s success-path _applyActive()); covers a delayed/dropped leavepictureinpicture\n } catch (e: any) {\n if (gen !== this._gen) return;\n this._setError(e);\n }\n }\n\n // --- Internal: API resolution (call-time, never cached — §3.7) ---\n\n // Unlike FullscreenCore's _elementFullscreenFn(), a naive direct property\n // lookup (`e.requestPictureInPicture`, walking the prototype chain) here is\n // safe: it cannot recurse into the Shell's own command method,\n // because the resolved target is validated to be a <video> element (§2)\n // before this is called, and <wcs-pip> (the Shell) is never itself a\n // <video>. Fullscreen's own→Element.prototype two-step resolution guards\n // against `target=\"self\"`/no-target resolving to the Shell element, which\n // cannot happen here.\n private _requestPictureInPictureFn(el: HTMLVideoElement): (() => Promise<PictureInPictureWindow>) | undefined {\n const e = el as any;\n return typeof e.requestPictureInPicture === \"function\" ? e.requestPictureInPicture : undefined;\n }\n\n private _exitPictureInPictureFn(): (() => Promise<void>) | undefined {\n const d = document as any;\n return typeof d.exitPictureInPicture === \"function\" ? d.exitPictureInPicture.bind(document) : undefined;\n }\n\n private _pictureInPictureElement(): Element | null {\n const d = document as any;\n return d.pictureInPictureElement ?? null;\n }\n\n // --- Internal: event wiring ---\n\n private _onEnter = (): void => {\n this._syncActive();\n };\n\n private _onLeave = (): void => {\n this._syncActive();\n };\n\n private _syncActive(): void {\n const isActive = this._video !== null && this._pictureInPictureElement() === this._video;\n this._setActive(isActive);\n }\n\n private _detach(): void {\n if (this._video) {\n this._video.removeEventListener(\"enterpictureinpicture\", this._onEnter);\n this._video.removeEventListener(\"leavepictureinpicture\", this._onLeave);\n }\n }\n\n // --- State setters with event dispatch (§3.3 same-value guard) ---\n\n private _setActive(active: boolean): void {\n if (this._active === active) return;\n this._active = active;\n this._target.dispatchEvent(new CustomEvent(\"wcs-pip:change\", {\n detail: { active },\n bubbles: true,\n }));\n }\n\n private _setError(error: any): void {\n this._error = error;\n }\n}\n","import { IWcBindable } from \"../types.js\";\nimport { PipCore } from \"../core/PipCore.js\";\n\n/**\n * `<wcs-pip target=\"...\">` — declarative Picture-in-Picture control.\n *\n * Like `<wcs-fullscreen>` (docs/fullscreen-tag-design.md §0/§1), this Shell\n * does not operate on itself: it is a non-visible control tag that resolves a\n * `target` element and invokes Picture-in-Picture commands against it. The\n * `target` attribute resolves in the same 3 modes as `intersection`/`fullscreen`\n * (`self` / a selector / the first element child), reused verbatim from\n * `@wcstack/intersection`'s `_resolveTarget()`/`_safeQuery()`\n * (packages/intersection/src/components/Intersect.ts).\n *\n * Picture-in-Picture-specific difference (docs/picture-in-picture-tag-design.md\n * §2): the resolved target must be a `<video>` element. This Shell resolves the\n * DOM element and hands it to the Core; the Core performs the `tagName ===\n * \"VIDEO\"` validation (never-throw — a mismatch is treated as an unresolved\n * target and reported via `error`, not thrown).\n */\nexport class WcsPip extends HTMLElement {\n // SSR (§4.4): observe() completes synchronously, but the Shell still exposes\n // connectedCallbackPromise so the state binder can await it uniformly across\n // all IO nodes before snapshotting.\n static hasConnectedCallbackPromise = true;\n\n static observedAttributes = [\"target\"];\n\n static wcBindable: IWcBindable = {\n ...PipCore.wcBindable,\n inputs: [{ name: \"target\", attribute: \"target\" }],\n // Core の commands をそのまま継承(単一情報源)。fullscreen/intersection と同型。\n commands: PipCore.wcBindable.commands,\n };\n\n private _core: PipCore;\n private _connectedCallbackPromise: Promise<void> = Promise.resolve();\n\n constructor() {\n super();\n this._core = new PipCore(this);\n }\n\n get connectedCallbackPromise(): Promise<void> {\n return this._connectedCallbackPromise;\n }\n\n // --- Attribute accessors ---\n\n get target(): string {\n return this.getAttribute(\"target\") ?? \"\";\n }\n\n set target(value: string) {\n this.setAttribute(\"target\", value);\n }\n\n // --- Core delegated getters ---\n\n get active(): boolean {\n return this._core.active;\n }\n\n get error(): any {\n return this._core.error;\n }\n\n // --- Commands ---\n\n async requestPictureInPicture(): Promise<void> {\n const { element } = this._resolveVideoTarget();\n return this._core.requestPictureInPicture(element);\n }\n\n async exitPictureInPicture(): Promise<void> {\n return this._core.exitPictureInPicture();\n }\n\n // --- Internal ---\n\n /**\n * `_resolveTarget()`/`_safeQuery()` copied verbatim from `@wcstack/intersection`\n * (packages/intersection/src/components/Intersect.ts:243-267, 281-287) per the\n * fullscreen/picture-in-picture batch's shared target-resolution archetype\n * (docs/fullscreen-tag-design.md §1).\n */\n private _resolveTarget(): { element: Element | null; display: string } {\n const target = this.target;\n if (target === \"self\") {\n return { element: this, display: \"block\" };\n }\n if (target !== \"\") {\n const scope = this.getRootNode() as Document | ShadowRoot;\n return { element: this._safeQuery(scope, target), display: \"none\" };\n }\n const child = this.firstElementChild;\n if (child) {\n return { element: child, display: \"contents\" };\n }\n return { element: this, display: \"block\" };\n }\n\n private _safeQuery(scope: Document | ShadowRoot, selector: string): Element | null {\n try {\n return scope.querySelector(selector);\n } catch {\n return null;\n }\n }\n\n /**\n * Layers the Picture-in-Picture-specific `tagName === \"VIDEO\"` check on top\n * of `_resolveTarget()` (docs/picture-in-picture-tag-design.md §2). A\n * resolved-but-wrong-tag element is treated as unresolved (`element: null`)\n * so it flows into the same \"target not found\" failure path as Fullscreen's\n * missing-target case — never-throw, no exception escapes.\n */\n private _resolveVideoTarget(): { element: HTMLVideoElement | null; display: string } {\n const { element, display } = this._resolveTarget();\n if (element !== null && element.tagName !== \"VIDEO\") {\n return { element: null, display };\n }\n return { element: element as HTMLVideoElement | null, display };\n }\n\n private _observe(): void {\n const { element, display } = this._resolveVideoTarget();\n this.style.display = display;\n this._connectedCallbackPromise = this._core.observe(element);\n }\n\n // --- Lifecycle ---\n\n connectedCallback(): void {\n this._observe();\n }\n\n disconnectedCallback(): void {\n this._core.dispose();\n }\n\n attributeChangedCallback(_name: string, oldValue: string | null, newValue: string | null): void {\n if (oldValue === newValue) return;\n if (!this.isConnected) return;\n this._observe();\n }\n}\n","import { WcsPip } from \"./components/Pip.js\";\nimport { config } from \"./config.js\";\n\nexport function registerComponents(): void {\n if (!customElements.get(config.tagNames.pip)) {\n customElements.define(config.tagNames.pip, WcsPip);\n }\n}\n","import { setConfig } from \"./config.js\";\nimport { registerComponents } from \"./registerComponents.js\";\nimport { IWritableConfig } from \"./types.js\";\n\nexport function bootstrapPip(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/PipCore.ts","../src/components/Pip.ts","../src/registerComponents.ts","../src/bootstrapPip.ts"],"sourcesContent":["import { IConfig, IWritableConfig } from \"./types.js\";\n\ninterface IInternalConfig extends IConfig {\n tagNames: {\n pip: string;\n };\n}\n\nconst _config: IInternalConfig = {\n tagNames: {\n pip: \"wcs-pip\",\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 } from \"../types.js\";\n\n/**\n * Headless Picture-in-Picture primitive. A thin, framework-agnostic wrapper\n * around the classic Picture-in-Picture API\n * (`HTMLVideoElement.requestPictureInPicture()` / `document.exitPictureInPicture()` /\n * `document.pictureInPictureElement`) exposed through the wc-bindable protocol.\n *\n * This Core follows the same basic pattern as `@wcstack/fullscreen`'s\n * `FullscreenCore` (docs/fullscreen-tag-design.md): target resolution is done\n * by the Shell (this Core receives the resolved element at call time), API\n * resolution is call-time/non-cached, `_gen` is a single Core-level generation\n * guard, and `error` is a simple single field (no permission-style 4-value\n * state). See docs/picture-in-picture-tag-design.md for the differences from\n * Fullscreen:\n *\n * - **§2 target constraint**: the resolved target MUST be a `<video>` element.\n * Picture-in-Picture is only defined as an instance method of\n * `HTMLVideoElement` — unlike Fullscreen, which any `Element` supports. A\n * non-`<video>` target is a never-throw failure: it is treated the same as\n * an unresolved target and reported via `error`.\n * - **§3 event subscription target**: `enterpictureinpicture` /\n * `leavepictureinpicture` fire on the `<video>` element itself, not on\n * `document` (the reverse of Fullscreen's `document`-level\n * `fullscreenchange`). The Core attaches/detaches these listeners directly\n * on the resolved `<video>` element, re-wiring them whenever the target is\n * re-resolved (e.g. the Shell's `target` attribute changes).\n */\nexport class PipCore extends EventTarget {\n static wcBindable: IWcBindable = {\n protocol: \"wc-bindable\",\n version: 1,\n properties: [\n { name: \"active\", event: \"wcs-pip:change\", getter: (e: Event) => (e as CustomEvent).detail.active },\n ],\n commands: [\n { name: \"requestPictureInPicture\", async: true },\n { name: \"exitPictureInPicture\", async: true },\n ],\n };\n\n private _target: EventTarget;\n private _active: boolean = false;\n private _error: any = null;\n\n // The <video> element the Core currently subscribes to for\n // enterpictureinpicture/leavepictureinpicture (null when unresolved/torn down).\n private _video: HTMLVideoElement | null = null;\n\n // Generation guard (§3.4 / fullscreen-tag-design.md §6): bumped on dispose()\n // and each async command start. A completion that lands after dispose() (or\n // after a superseding call) is stale and MUST NOT write state.\n private _gen = 0;\n\n // SSR (§3.8): no asynchronous probe to await, so readiness is immediate.\n private _ready: Promise<void> = Promise.resolve();\n\n constructor(target?: EventTarget) {\n super();\n this._target = target ?? this;\n }\n\n get ready(): Promise<void> {\n return this._ready;\n }\n\n get active(): boolean {\n return this._active;\n }\n\n get error(): any {\n return this._error;\n }\n\n // --- Lifecycle (§3.5) ---\n\n /**\n * (Re-)subscribe to `enterpictureinpicture`/`leavepictureinpicture` on\n * `element` (the Shell's resolved `<video>` target). Idempotent when called\n * again with the same element; re-wires the listeners when the element\n * changes (e.g. the `target` attribute was changed), detaching from the\n * previous element first so no stale listener lingers.\n */\n observe(element: HTMLVideoElement | null): Promise<void> {\n if (this._video === element) {\n return this._ready;\n }\n this._detach();\n this._video = element;\n if (element) {\n element.addEventListener(\"enterpictureinpicture\", this._onEnter);\n element.addEventListener(\"leavepictureinpicture\", this._onLeave);\n }\n this._syncActive();\n return this._ready;\n }\n\n dispose(): void {\n this._gen++;\n this._detach();\n this._video = null;\n }\n\n // --- Commands (§3.6 never-throw) ---\n\n /**\n * Request Picture-in-Picture for `element`. `element` must be a `<video>`\n * (checked before the gesture-context failure path, since a type mismatch is\n * an environment-independent, permanent error — docs/picture-in-picture-tag-design.md §2).\n * Never throws: all failures (wrong tag, unsupported API, gesture-context\n * rejection) are funneled into `error` and the returned promise resolves.\n */\n async requestPictureInPicture(element: HTMLVideoElement | null): Promise<void> {\n const gen = ++this._gen;\n if (!element || element.tagName !== \"VIDEO\") {\n this._setError({ message: \"target must be a <video> element.\" });\n return;\n }\n // Re-wire to `element` before issuing the platform call: a caller may\n // request a <video> different from the one last passed to observe() (e.g.\n // the Shell's target attribute pointed at nothing at connect time and the\n // matching <video> was only inserted later, so no attributeChangedCallback\n // ever re-resolved it). Without this, `_video` stays stale and\n // `_syncActive()` below (and future enter/leave events) would never\n // recognize `element` as this Core's target, leaving `active` permanently\n // wrong even though the request succeeded (mirrors\n // FullscreenCore.requestFullscreen()'s unconditional `this._resolvedTarget\n // = element` assignment — docs/fullscreen-tag-design.md §6).\n this.observe(element);\n const fn = this._requestPictureInPictureFn(element);\n if (!fn) {\n this._setError({ message: \"Picture-in-Picture API is not supported.\" });\n return;\n }\n try {\n await fn.call(element);\n if (gen !== this._gen) return; // stale\n this._setError(null);\n this._syncActive(); // belt-and-suspenders (mirrors FullscreenCore's _applyActive() on success)\n } catch (e: any) {\n if (gen !== this._gen) return; // stale\n this._setError(e); // e.g. NotAllowedError (gesture-context rejection)\n }\n }\n\n /**\n * Exit Picture-in-Picture. Mirrors FullscreenCore.exitFullscreen(): a\n * silent no-op (resolve, no error) when nothing is currently in\n * Picture-in-Picture — see fullscreen-tag-design.md §7.\n */\n async exitPictureInPicture(): Promise<void> {\n // no-op checks come BEFORE the generation bump: a call that does nothing\n // must not supersede an in-flight requestPictureInPicture() — bumping\n // first would make the pending request's settle handling stale and\n // silently swallow its error update (mirrors\n // FullscreenCore.exitFullscreen()).\n if (this._pictureInPictureElement() === null) return; // already not in PiP: silent no-op\n const fn = this._exitPictureInPictureFn();\n if (!fn) return; // unsupported: silent no-op (semantically already \"not in PiP\")\n const gen = ++this._gen;\n try {\n await fn();\n if (gen !== this._gen) return;\n this._setError(null);\n this._syncActive(); // belt-and-suspenders (mirrors FullscreenCore.exitFullscreen()'s success-path _applyActive()); covers a delayed/dropped leavepictureinpicture\n } catch (e: any) {\n if (gen !== this._gen) return;\n this._setError(e);\n }\n }\n\n // --- Internal: API resolution (call-time, never cached — §3.7) ---\n\n // Unlike FullscreenCore's _elementFullscreenFn(), a naive direct property\n // lookup (`e.requestPictureInPicture`, walking the prototype chain) here is\n // safe: it cannot recurse into the Shell's own command method,\n // because the resolved target is validated to be a <video> element (§2)\n // before this is called, and <wcs-pip> (the Shell) is never itself a\n // <video>. Fullscreen's own→Element.prototype two-step resolution guards\n // against `target=\"self\"`/no-target resolving to the Shell element, which\n // cannot happen here.\n private _requestPictureInPictureFn(el: HTMLVideoElement): (() => Promise<PictureInPictureWindow>) | undefined {\n const e = el as any;\n return typeof e.requestPictureInPicture === \"function\" ? e.requestPictureInPicture : undefined;\n }\n\n private _exitPictureInPictureFn(): (() => Promise<void>) | undefined {\n const d = document as any;\n return typeof d.exitPictureInPicture === \"function\" ? d.exitPictureInPicture.bind(document) : undefined;\n }\n\n private _pictureInPictureElement(): Element | null {\n const d = document as any;\n return d.pictureInPictureElement ?? null;\n }\n\n // --- Internal: event wiring ---\n\n private _onEnter = (): void => {\n this._syncActive();\n };\n\n private _onLeave = (): void => {\n this._syncActive();\n };\n\n private _syncActive(): void {\n const isActive = this._video !== null && this._pictureInPictureElement() === this._video;\n this._setActive(isActive);\n }\n\n private _detach(): void {\n if (this._video) {\n this._video.removeEventListener(\"enterpictureinpicture\", this._onEnter);\n this._video.removeEventListener(\"leavepictureinpicture\", this._onLeave);\n }\n }\n\n // --- State setters with event dispatch (§3.3 same-value guard) ---\n\n private _setActive(active: boolean): void {\n if (this._active === active) return;\n this._active = active;\n this._target.dispatchEvent(new CustomEvent(\"wcs-pip:change\", {\n detail: { active },\n bubbles: true,\n }));\n }\n\n private _setError(error: any): void {\n this._error = error;\n }\n}\n","import { IWcBindable } from \"../types.js\";\nimport { PipCore } from \"../core/PipCore.js\";\n\n/**\n * `<wcs-pip target=\"...\">` — declarative Picture-in-Picture control.\n *\n * Like `<wcs-fullscreen>` (docs/fullscreen-tag-design.md §0/§1), this Shell\n * does not operate on itself: it is a non-visible control tag that resolves a\n * `target` element and invokes Picture-in-Picture commands against it. The\n * `target` attribute resolves in the same 3 modes as `intersection`/`fullscreen`\n * (`self` / a selector / the first element child), reused verbatim from\n * `@wcstack/intersection`'s `_resolveTarget()`/`_safeQuery()`\n * (packages/intersection/src/components/Intersect.ts).\n *\n * Picture-in-Picture-specific difference (docs/picture-in-picture-tag-design.md\n * §2): the resolved target must be a `<video>` element. This Shell resolves the\n * DOM element and hands it to the Core; the Core performs the `tagName ===\n * \"VIDEO\"` validation (never-throw — a mismatch is treated as an unresolved\n * target and reported via `error`, not thrown).\n */\nexport class WcsPip extends HTMLElement {\n // SSR (§4.4): observe() completes synchronously, but the Shell still exposes\n // connectedCallbackPromise so the state binder can await it uniformly across\n // all IO nodes before snapshotting.\n static hasConnectedCallbackPromise = true;\n\n static observedAttributes = [\"target\"];\n\n static wcBindable: IWcBindable = {\n ...PipCore.wcBindable,\n inputs: [{ name: \"target\", attribute: \"target\" }],\n // Core の commands をそのまま継承(単一情報源)。fullscreen/intersection と同型。\n commands: PipCore.wcBindable.commands,\n };\n\n private _core: PipCore;\n private _connectedCallbackPromise: Promise<void> = Promise.resolve();\n private _internals: ElementInternals | null = null;\n\n constructor() {\n super();\n this._core = new PipCore(this);\n this._internals = this._initInternals();\n this._wireStates({\n \"wcs-pip:change\": (d) => ({ active: d?.active === true }),\n });\n }\n\n // CSS state reflection (:state()) — debug-only snapshot getter. NOT part of\n // wc-bindable (not a bind target); see README \"CSS styling with :state()\".\n // MUST NOT return the live CustomStateSet (that would let callers write\n // states from outside, defeating the point of :state() being read-only).\n get debugStates(): string[] {\n return this._internals ? [...this._internals.states] : [];\n }\n\n private _initInternals(): ElementInternals | null {\n // never-throw (docs/custom-state-reflection-design.md §3.1): attachInternals\n // is absent in happy-dom / older environments, and pre-125 Chromium rejects\n // non-dashed state names from states.add() (probed and discarded here).\n // Either case silently disables reflection — the component still works,\n // it just doesn't expose :state() selectors.\n try {\n if (typeof this.attachInternals !== \"function\") return null;\n const internals = this.attachInternals();\n internals.states.add(\"wcs-probe\");\n internals.states.delete(\"wcs-probe\");\n return internals;\n } catch {\n return null;\n }\n }\n\n private _wireStates(map: Record<string, (detail: any) => Record<string, boolean>>): void {\n if (this._internals === null) return;\n const states = this._internals.states;\n for (const [event, toStates] of Object.entries(map)) {\n this.addEventListener(event, (e) => {\n const debug = this.hasAttribute(\"debug-states\");\n for (const [name, on] of Object.entries(toStates((e as CustomEvent).detail))) {\n try {\n if (on) { states.add(name); } else { states.delete(name); }\n } catch { /* never-throw */ }\n if (debug) this.toggleAttribute(`data-wcs-state-${name}`, on);\n }\n });\n }\n }\n\n get connectedCallbackPromise(): Promise<void> {\n return this._connectedCallbackPromise;\n }\n\n // --- Attribute accessors ---\n\n get target(): string {\n return this.getAttribute(\"target\") ?? \"\";\n }\n\n set target(value: string) {\n this.setAttribute(\"target\", value);\n }\n\n // --- Core delegated getters ---\n\n get active(): boolean {\n return this._core.active;\n }\n\n get error(): any {\n return this._core.error;\n }\n\n // --- Commands ---\n\n async requestPictureInPicture(): Promise<void> {\n const { element } = this._resolveVideoTarget();\n return this._core.requestPictureInPicture(element);\n }\n\n async exitPictureInPicture(): Promise<void> {\n return this._core.exitPictureInPicture();\n }\n\n // --- Internal ---\n\n /**\n * `_resolveTarget()`/`_safeQuery()` copied verbatim from `@wcstack/intersection`\n * (packages/intersection/src/components/Intersect.ts:243-267, 281-287) per the\n * fullscreen/picture-in-picture batch's shared target-resolution archetype\n * (docs/fullscreen-tag-design.md §1).\n */\n private _resolveTarget(): { element: Element | null; display: string } {\n const target = this.target;\n if (target === \"self\") {\n return { element: this, display: \"block\" };\n }\n if (target !== \"\") {\n const scope = this.getRootNode() as Document | ShadowRoot;\n return { element: this._safeQuery(scope, target), display: \"none\" };\n }\n const child = this.firstElementChild;\n if (child) {\n return { element: child, display: \"contents\" };\n }\n return { element: this, display: \"block\" };\n }\n\n private _safeQuery(scope: Document | ShadowRoot, selector: string): Element | null {\n try {\n return scope.querySelector(selector);\n } catch {\n return null;\n }\n }\n\n /**\n * Layers the Picture-in-Picture-specific `tagName === \"VIDEO\"` check on top\n * of `_resolveTarget()` (docs/picture-in-picture-tag-design.md §2). A\n * resolved-but-wrong-tag element is treated as unresolved (`element: null`)\n * so it flows into the same \"target not found\" failure path as Fullscreen's\n * missing-target case — never-throw, no exception escapes.\n */\n private _resolveVideoTarget(): { element: HTMLVideoElement | null; display: string } {\n const { element, display } = this._resolveTarget();\n if (element !== null && element.tagName !== \"VIDEO\") {\n return { element: null, display };\n }\n return { element: element as HTMLVideoElement | null, display };\n }\n\n private _observe(): void {\n const { element, display } = this._resolveVideoTarget();\n this.style.display = display;\n this._connectedCallbackPromise = this._core.observe(element);\n }\n\n // --- Lifecycle ---\n\n connectedCallback(): void {\n this._observe();\n }\n\n disconnectedCallback(): void {\n this._core.dispose();\n }\n\n attributeChangedCallback(_name: string, oldValue: string | null, newValue: string | null): void {\n if (oldValue === newValue) return;\n if (!this.isConnected) return;\n this._observe();\n }\n}\n","import { WcsPip } from \"./components/Pip.js\";\nimport { config } from \"./config.js\";\n\nexport function registerComponents(): void {\n if (!customElements.get(config.tagNames.pip)) {\n customElements.define(config.tagNames.pip, WcsPip);\n }\n}\n","import { setConfig } from \"./config.js\";\nimport { registerComponents } from \"./registerComponents.js\";\nimport { IWritableConfig } from \"./types.js\";\n\nexport function bootstrapPip(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:{pip:"wcs-pip"}};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 i of Object.keys(e))t[i]=r(e[i]);return t}let i=null;const s=e;function n(){return i||(i=t(r(e))),i}class c extends EventTarget{static wcBindable={protocol:"wc-bindable",version:1,properties:[{name:"active",event:"wcs-pip:change",getter:e=>e.detail.active}],commands:[{name:"requestPictureInPicture",async:!0},{name:"exitPictureInPicture",async:!0}]};_target;_active=!1;_error=null;_video=null;_gen=0;_ready=Promise.resolve();constructor(e){super(),this._target=e??this}get ready(){return this._ready}get active(){return this._active}get error(){return this._error}observe(e){return this._video===e||(this._detach(),this._video=e,e&&(e.addEventListener("enterpictureinpicture",this._onEnter),e.addEventListener("leavepictureinpicture",this._onLeave)),this._syncActive()),this._ready}dispose(){this._gen++,this._detach(),this._video=null}async requestPictureInPicture(e){const t=++this._gen;if(!e||"VIDEO"!==e.tagName)return void this._setError({message:"target must be a <video> element."});this.observe(e);const r=this._requestPictureInPictureFn(e);if(r)try{if(await r.call(e),t!==this._gen)return;this._setError(null),this._syncActive()}catch(e){if(t!==this._gen)return;this._setError(e)}else this._setError({message:"Picture-in-Picture API is not supported."})}async exitPictureInPicture(){if(null===this._pictureInPictureElement())return;const e=this._exitPictureInPictureFn();if(!e)return;const t=++this._gen;try{if(await e(),t!==this._gen)return;this._setError(null),this._syncActive()}catch(e){if(t!==this._gen)return;this._setError(e)}}_requestPictureInPictureFn(e){const t=e;return"function"==typeof t.requestPictureInPicture?t.requestPictureInPicture:void 0}_exitPictureInPictureFn(){const e=document;return"function"==typeof e.exitPictureInPicture?e.exitPictureInPicture.bind(document):void 0}_pictureInPictureElement(){return document.pictureInPictureElement??null}_onEnter=()=>{this._syncActive()};_onLeave=()=>{this._syncActive()};_syncActive(){const e=null!==this._video&&this._pictureInPictureElement()===this._video;this._setActive(e)}_detach(){this._video&&(this._video.removeEventListener("enterpictureinpicture",this._onEnter),this._video.removeEventListener("leavepictureinpicture",this._onLeave))}_setActive(e){this._active!==e&&(this._active=e,this._target.dispatchEvent(new CustomEvent("wcs-pip:change",{detail:{active:e},bubbles:!0})))}_setError(e){this._error=e}}class o extends HTMLElement{static hasConnectedCallbackPromise=!0;static observedAttributes=["target"];static wcBindable={...c.wcBindable,inputs:[{name:"target",attribute:"target"}],commands:c.wcBindable.commands};_core;_connectedCallbackPromise=Promise.resolve();constructor(){super(),this._core=new c(this)}get connectedCallbackPromise(){return this._connectedCallbackPromise}get target(){return this.getAttribute("target")??""}set target(e){this.setAttribute("target",e)}get active(){return this._core.active}get error(){return this._core.error}async requestPictureInPicture(){const{element:e}=this._resolveVideoTarget();return this._core.requestPictureInPicture(e)}async exitPictureInPicture(){return this._core.exitPictureInPicture()}_resolveTarget(){const e=this.target;if("self"===e)return{element:this,display:"block"};if(""!==e){const t=this.getRootNode();return{element:this._safeQuery(t,e),display:"none"}}const t=this.firstElementChild;return t?{element:t,display:"contents"}:{element:this,display:"block"}}_safeQuery(e,t){try{return e.querySelector(t)}catch{return null}}_resolveVideoTarget(){const{element:e,display:t}=this._resolveTarget();return null!==e&&"VIDEO"!==e.tagName?{element:null,display:t}:{element:e,display:t}}_observe(){const{element:e,display:t}=this._resolveVideoTarget();this.style.display=t,this._connectedCallbackPromise=this._core.observe(e)}connectedCallback(){this._observe()}disconnectedCallback(){this._core.dispose()}attributeChangedCallback(e,t,r){t!==r&&this.isConnected&&this._observe()}}function u(t){var r;t&&((r=t).tagNames&&Object.assign(e.tagNames,r.tagNames),i=null),customElements.get(s.tagNames.pip)||customElements.define(s.tagNames.pip,o)}export{c as PipCore,o as WcsPip,u as bootstrapPip,n as getConfig};
1
+ const e={tagNames:{pip:"wcs-pip"}};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 i of Object.keys(e))t[i]=r(e[i]);return t}let i=null;const s=e;function n(){return i||(i=t(r(e))),i}class c extends EventTarget{static wcBindable={protocol:"wc-bindable",version:1,properties:[{name:"active",event:"wcs-pip:change",getter:e=>e.detail.active}],commands:[{name:"requestPictureInPicture",async:!0},{name:"exitPictureInPicture",async:!0}]};_target;_active=!1;_error=null;_video=null;_gen=0;_ready=Promise.resolve();constructor(e){super(),this._target=e??this}get ready(){return this._ready}get active(){return this._active}get error(){return this._error}observe(e){return this._video===e||(this._detach(),this._video=e,e&&(e.addEventListener("enterpictureinpicture",this._onEnter),e.addEventListener("leavepictureinpicture",this._onLeave)),this._syncActive()),this._ready}dispose(){this._gen++,this._detach(),this._video=null}async requestPictureInPicture(e){const t=++this._gen;if(!e||"VIDEO"!==e.tagName)return void this._setError({message:"target must be a <video> element."});this.observe(e);const r=this._requestPictureInPictureFn(e);if(r)try{if(await r.call(e),t!==this._gen)return;this._setError(null),this._syncActive()}catch(e){if(t!==this._gen)return;this._setError(e)}else this._setError({message:"Picture-in-Picture API is not supported."})}async exitPictureInPicture(){if(null===this._pictureInPictureElement())return;const e=this._exitPictureInPictureFn();if(!e)return;const t=++this._gen;try{if(await e(),t!==this._gen)return;this._setError(null),this._syncActive()}catch(e){if(t!==this._gen)return;this._setError(e)}}_requestPictureInPictureFn(e){const t=e;return"function"==typeof t.requestPictureInPicture?t.requestPictureInPicture:void 0}_exitPictureInPictureFn(){const e=document;return"function"==typeof e.exitPictureInPicture?e.exitPictureInPicture.bind(document):void 0}_pictureInPictureElement(){return document.pictureInPictureElement??null}_onEnter=()=>{this._syncActive()};_onLeave=()=>{this._syncActive()};_syncActive(){const e=null!==this._video&&this._pictureInPictureElement()===this._video;this._setActive(e)}_detach(){this._video&&(this._video.removeEventListener("enterpictureinpicture",this._onEnter),this._video.removeEventListener("leavepictureinpicture",this._onLeave))}_setActive(e){this._active!==e&&(this._active=e,this._target.dispatchEvent(new CustomEvent("wcs-pip:change",{detail:{active:e},bubbles:!0})))}_setError(e){this._error=e}}class a extends HTMLElement{static hasConnectedCallbackPromise=!0;static observedAttributes=["target"];static wcBindable={...c.wcBindable,inputs:[{name:"target",attribute:"target"}],commands:c.wcBindable.commands};_core;_connectedCallbackPromise=Promise.resolve();_internals=null;constructor(){super(),this._core=new c(this),this._internals=this._initInternals(),this._wireStates({"wcs-pip:change":e=>({active:!0===e?.active})})}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,i]of Object.entries(e))this.addEventListener(r,e=>{const r=this.hasAttribute("debug-states");for(const[s,n]of Object.entries(i(e.detail))){try{n?t.add(s):t.delete(s)}catch{}r&&this.toggleAttribute(`data-wcs-state-${s}`,n)}})}get connectedCallbackPromise(){return this._connectedCallbackPromise}get target(){return this.getAttribute("target")??""}set target(e){this.setAttribute("target",e)}get active(){return this._core.active}get error(){return this._core.error}async requestPictureInPicture(){const{element:e}=this._resolveVideoTarget();return this._core.requestPictureInPicture(e)}async exitPictureInPicture(){return this._core.exitPictureInPicture()}_resolveTarget(){const e=this.target;if("self"===e)return{element:this,display:"block"};if(""!==e){const t=this.getRootNode();return{element:this._safeQuery(t,e),display:"none"}}const t=this.firstElementChild;return t?{element:t,display:"contents"}:{element:this,display:"block"}}_safeQuery(e,t){try{return e.querySelector(t)}catch{return null}}_resolveVideoTarget(){const{element:e,display:t}=this._resolveTarget();return null!==e&&"VIDEO"!==e.tagName?{element:null,display:t}:{element:e,display:t}}_observe(){const{element:e,display:t}=this._resolveVideoTarget();this.style.display=t,this._connectedCallbackPromise=this._core.observe(e)}connectedCallback(){this._observe()}disconnectedCallback(){this._core.dispose()}attributeChangedCallback(e,t,r){t!==r&&this.isConnected&&this._observe()}}function o(t){var r;t&&((r=t).tagNames&&Object.assign(e.tagNames,r.tagNames),i=null),customElements.get(s.tagNames.pip)||customElements.define(s.tagNames.pip,a)}export{c as PipCore,a as WcsPip,o as bootstrapPip,n 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/PipCore.ts","../src/components/Pip.ts","../src/bootstrapPip.ts","../src/registerComponents.ts"],"sourcesContent":["import { IConfig, IWritableConfig } from \"./types.js\";\n\ninterface IInternalConfig extends IConfig {\n tagNames: {\n pip: string;\n };\n}\n\nconst _config: IInternalConfig = {\n tagNames: {\n pip: \"wcs-pip\",\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 } from \"../types.js\";\n\n/**\n * Headless Picture-in-Picture primitive. A thin, framework-agnostic wrapper\n * around the classic Picture-in-Picture API\n * (`HTMLVideoElement.requestPictureInPicture()` / `document.exitPictureInPicture()` /\n * `document.pictureInPictureElement`) exposed through the wc-bindable protocol.\n *\n * This Core follows the same basic pattern as `@wcstack/fullscreen`'s\n * `FullscreenCore` (docs/fullscreen-tag-design.md): target resolution is done\n * by the Shell (this Core receives the resolved element at call time), API\n * resolution is call-time/non-cached, `_gen` is a single Core-level generation\n * guard, and `error` is a simple single field (no permission-style 4-value\n * state). See docs/picture-in-picture-tag-design.md for the differences from\n * Fullscreen:\n *\n * - **§2 target constraint**: the resolved target MUST be a `<video>` element.\n * Picture-in-Picture is only defined as an instance method of\n * `HTMLVideoElement` — unlike Fullscreen, which any `Element` supports. A\n * non-`<video>` target is a never-throw failure: it is treated the same as\n * an unresolved target and reported via `error`.\n * - **§3 event subscription target**: `enterpictureinpicture` /\n * `leavepictureinpicture` fire on the `<video>` element itself, not on\n * `document` (the reverse of Fullscreen's `document`-level\n * `fullscreenchange`). The Core attaches/detaches these listeners directly\n * on the resolved `<video>` element, re-wiring them whenever the target is\n * re-resolved (e.g. the Shell's `target` attribute changes).\n */\nexport class PipCore extends EventTarget {\n static wcBindable: IWcBindable = {\n protocol: \"wc-bindable\",\n version: 1,\n properties: [\n { name: \"active\", event: \"wcs-pip:change\", getter: (e: Event) => (e as CustomEvent).detail.active },\n ],\n commands: [\n { name: \"requestPictureInPicture\", async: true },\n { name: \"exitPictureInPicture\", async: true },\n ],\n };\n\n private _target: EventTarget;\n private _active: boolean = false;\n private _error: any = null;\n\n // The <video> element the Core currently subscribes to for\n // enterpictureinpicture/leavepictureinpicture (null when unresolved/torn down).\n private _video: HTMLVideoElement | null = null;\n\n // Generation guard (§3.4 / fullscreen-tag-design.md §6): bumped on dispose()\n // and each async command start. A completion that lands after dispose() (or\n // after a superseding call) is stale and MUST NOT write state.\n private _gen = 0;\n\n // SSR (§3.8): no asynchronous probe to await, so readiness is immediate.\n private _ready: Promise<void> = Promise.resolve();\n\n constructor(target?: EventTarget) {\n super();\n this._target = target ?? this;\n }\n\n get ready(): Promise<void> {\n return this._ready;\n }\n\n get active(): boolean {\n return this._active;\n }\n\n get error(): any {\n return this._error;\n }\n\n // --- Lifecycle (§3.5) ---\n\n /**\n * (Re-)subscribe to `enterpictureinpicture`/`leavepictureinpicture` on\n * `element` (the Shell's resolved `<video>` target). Idempotent when called\n * again with the same element; re-wires the listeners when the element\n * changes (e.g. the `target` attribute was changed), detaching from the\n * previous element first so no stale listener lingers.\n */\n observe(element: HTMLVideoElement | null): Promise<void> {\n if (this._video === element) {\n return this._ready;\n }\n this._detach();\n this._video = element;\n if (element) {\n element.addEventListener(\"enterpictureinpicture\", this._onEnter);\n element.addEventListener(\"leavepictureinpicture\", this._onLeave);\n }\n this._syncActive();\n return this._ready;\n }\n\n dispose(): void {\n this._gen++;\n this._detach();\n this._video = null;\n }\n\n // --- Commands (§3.6 never-throw) ---\n\n /**\n * Request Picture-in-Picture for `element`. `element` must be a `<video>`\n * (checked before the gesture-context failure path, since a type mismatch is\n * an environment-independent, permanent error — docs/picture-in-picture-tag-design.md §2).\n * Never throws: all failures (wrong tag, unsupported API, gesture-context\n * rejection) are funneled into `error` and the returned promise resolves.\n */\n async requestPictureInPicture(element: HTMLVideoElement | null): Promise<void> {\n const gen = ++this._gen;\n if (!element || element.tagName !== \"VIDEO\") {\n this._setError({ message: \"target must be a <video> element.\" });\n return;\n }\n // Re-wire to `element` before issuing the platform call: a caller may\n // request a <video> different from the one last passed to observe() (e.g.\n // the Shell's target attribute pointed at nothing at connect time and the\n // matching <video> was only inserted later, so no attributeChangedCallback\n // ever re-resolved it). Without this, `_video` stays stale and\n // `_syncActive()` below (and future enter/leave events) would never\n // recognize `element` as this Core's target, leaving `active` permanently\n // wrong even though the request succeeded (mirrors\n // FullscreenCore.requestFullscreen()'s unconditional `this._resolvedTarget\n // = element` assignment — docs/fullscreen-tag-design.md §6).\n this.observe(element);\n const fn = this._requestPictureInPictureFn(element);\n if (!fn) {\n this._setError({ message: \"Picture-in-Picture API is not supported.\" });\n return;\n }\n try {\n await fn.call(element);\n if (gen !== this._gen) return; // stale\n this._setError(null);\n this._syncActive(); // belt-and-suspenders (mirrors FullscreenCore's _applyActive() on success)\n } catch (e: any) {\n if (gen !== this._gen) return; // stale\n this._setError(e); // e.g. NotAllowedError (gesture-context rejection)\n }\n }\n\n /**\n * Exit Picture-in-Picture. Mirrors FullscreenCore.exitFullscreen(): a\n * silent no-op (resolve, no error) when nothing is currently in\n * Picture-in-Picture — see fullscreen-tag-design.md §7.\n */\n async exitPictureInPicture(): Promise<void> {\n // no-op checks come BEFORE the generation bump: a call that does nothing\n // must not supersede an in-flight requestPictureInPicture() — bumping\n // first would make the pending request's settle handling stale and\n // silently swallow its error update (mirrors\n // FullscreenCore.exitFullscreen()).\n if (this._pictureInPictureElement() === null) return; // already not in PiP: silent no-op\n const fn = this._exitPictureInPictureFn();\n if (!fn) return; // unsupported: silent no-op (semantically already \"not in PiP\")\n const gen = ++this._gen;\n try {\n await fn();\n if (gen !== this._gen) return;\n this._setError(null);\n this._syncActive(); // belt-and-suspenders (mirrors FullscreenCore.exitFullscreen()'s success-path _applyActive()); covers a delayed/dropped leavepictureinpicture\n } catch (e: any) {\n if (gen !== this._gen) return;\n this._setError(e);\n }\n }\n\n // --- Internal: API resolution (call-time, never cached — §3.7) ---\n\n // Unlike FullscreenCore's _elementFullscreenFn(), a naive direct property\n // lookup (`e.requestPictureInPicture`, walking the prototype chain) here is\n // safe: it cannot recurse into the Shell's own command method,\n // because the resolved target is validated to be a <video> element (§2)\n // before this is called, and <wcs-pip> (the Shell) is never itself a\n // <video>. Fullscreen's own→Element.prototype two-step resolution guards\n // against `target=\"self\"`/no-target resolving to the Shell element, which\n // cannot happen here.\n private _requestPictureInPictureFn(el: HTMLVideoElement): (() => Promise<PictureInPictureWindow>) | undefined {\n const e = el as any;\n return typeof e.requestPictureInPicture === \"function\" ? e.requestPictureInPicture : undefined;\n }\n\n private _exitPictureInPictureFn(): (() => Promise<void>) | undefined {\n const d = document as any;\n return typeof d.exitPictureInPicture === \"function\" ? d.exitPictureInPicture.bind(document) : undefined;\n }\n\n private _pictureInPictureElement(): Element | null {\n const d = document as any;\n return d.pictureInPictureElement ?? null;\n }\n\n // --- Internal: event wiring ---\n\n private _onEnter = (): void => {\n this._syncActive();\n };\n\n private _onLeave = (): void => {\n this._syncActive();\n };\n\n private _syncActive(): void {\n const isActive = this._video !== null && this._pictureInPictureElement() === this._video;\n this._setActive(isActive);\n }\n\n private _detach(): void {\n if (this._video) {\n this._video.removeEventListener(\"enterpictureinpicture\", this._onEnter);\n this._video.removeEventListener(\"leavepictureinpicture\", this._onLeave);\n }\n }\n\n // --- State setters with event dispatch (§3.3 same-value guard) ---\n\n private _setActive(active: boolean): void {\n if (this._active === active) return;\n this._active = active;\n this._target.dispatchEvent(new CustomEvent(\"wcs-pip:change\", {\n detail: { active },\n bubbles: true,\n }));\n }\n\n private _setError(error: any): void {\n this._error = error;\n }\n}\n","import { IWcBindable } from \"../types.js\";\nimport { PipCore } from \"../core/PipCore.js\";\n\n/**\n * `<wcs-pip target=\"...\">` — declarative Picture-in-Picture control.\n *\n * Like `<wcs-fullscreen>` (docs/fullscreen-tag-design.md §0/§1), this Shell\n * does not operate on itself: it is a non-visible control tag that resolves a\n * `target` element and invokes Picture-in-Picture commands against it. The\n * `target` attribute resolves in the same 3 modes as `intersection`/`fullscreen`\n * (`self` / a selector / the first element child), reused verbatim from\n * `@wcstack/intersection`'s `_resolveTarget()`/`_safeQuery()`\n * (packages/intersection/src/components/Intersect.ts).\n *\n * Picture-in-Picture-specific difference (docs/picture-in-picture-tag-design.md\n * §2): the resolved target must be a `<video>` element. This Shell resolves the\n * DOM element and hands it to the Core; the Core performs the `tagName ===\n * \"VIDEO\"` validation (never-throw — a mismatch is treated as an unresolved\n * target and reported via `error`, not thrown).\n */\nexport class WcsPip extends HTMLElement {\n // SSR (§4.4): observe() completes synchronously, but the Shell still exposes\n // connectedCallbackPromise so the state binder can await it uniformly across\n // all IO nodes before snapshotting.\n static hasConnectedCallbackPromise = true;\n\n static observedAttributes = [\"target\"];\n\n static wcBindable: IWcBindable = {\n ...PipCore.wcBindable,\n inputs: [{ name: \"target\", attribute: \"target\" }],\n // Core の commands をそのまま継承(単一情報源)。fullscreen/intersection と同型。\n commands: PipCore.wcBindable.commands,\n };\n\n private _core: PipCore;\n private _connectedCallbackPromise: Promise<void> = Promise.resolve();\n\n constructor() {\n super();\n this._core = new PipCore(this);\n }\n\n get connectedCallbackPromise(): Promise<void> {\n return this._connectedCallbackPromise;\n }\n\n // --- Attribute accessors ---\n\n get target(): string {\n return this.getAttribute(\"target\") ?? \"\";\n }\n\n set target(value: string) {\n this.setAttribute(\"target\", value);\n }\n\n // --- Core delegated getters ---\n\n get active(): boolean {\n return this._core.active;\n }\n\n get error(): any {\n return this._core.error;\n }\n\n // --- Commands ---\n\n async requestPictureInPicture(): Promise<void> {\n const { element } = this._resolveVideoTarget();\n return this._core.requestPictureInPicture(element);\n }\n\n async exitPictureInPicture(): Promise<void> {\n return this._core.exitPictureInPicture();\n }\n\n // --- Internal ---\n\n /**\n * `_resolveTarget()`/`_safeQuery()` copied verbatim from `@wcstack/intersection`\n * (packages/intersection/src/components/Intersect.ts:243-267, 281-287) per the\n * fullscreen/picture-in-picture batch's shared target-resolution archetype\n * (docs/fullscreen-tag-design.md §1).\n */\n private _resolveTarget(): { element: Element | null; display: string } {\n const target = this.target;\n if (target === \"self\") {\n return { element: this, display: \"block\" };\n }\n if (target !== \"\") {\n const scope = this.getRootNode() as Document | ShadowRoot;\n return { element: this._safeQuery(scope, target), display: \"none\" };\n }\n const child = this.firstElementChild;\n if (child) {\n return { element: child, display: \"contents\" };\n }\n return { element: this, display: \"block\" };\n }\n\n private _safeQuery(scope: Document | ShadowRoot, selector: string): Element | null {\n try {\n return scope.querySelector(selector);\n } catch {\n return null;\n }\n }\n\n /**\n * Layers the Picture-in-Picture-specific `tagName === \"VIDEO\"` check on top\n * of `_resolveTarget()` (docs/picture-in-picture-tag-design.md §2). A\n * resolved-but-wrong-tag element is treated as unresolved (`element: null`)\n * so it flows into the same \"target not found\" failure path as Fullscreen's\n * missing-target case — never-throw, no exception escapes.\n */\n private _resolveVideoTarget(): { element: HTMLVideoElement | null; display: string } {\n const { element, display } = this._resolveTarget();\n if (element !== null && element.tagName !== \"VIDEO\") {\n return { element: null, display };\n }\n return { element: element as HTMLVideoElement | null, display };\n }\n\n private _observe(): void {\n const { element, display } = this._resolveVideoTarget();\n this.style.display = display;\n this._connectedCallbackPromise = this._core.observe(element);\n }\n\n // --- Lifecycle ---\n\n connectedCallback(): void {\n this._observe();\n }\n\n disconnectedCallback(): void {\n this._core.dispose();\n }\n\n attributeChangedCallback(_name: string, oldValue: string | null, newValue: string | null): void {\n if (oldValue === newValue) return;\n if (!this.isConnected) return;\n this._observe();\n }\n}\n","import { setConfig } from \"./config.js\";\nimport { registerComponents } from \"./registerComponents.js\";\nimport { IWritableConfig } from \"./types.js\";\n\nexport function bootstrapPip(userConfig?: IWritableConfig): void {\n if (userConfig) {\n setConfig(userConfig);\n }\n registerComponents();\n}\n","import { WcsPip } from \"./components/Pip.js\";\nimport { config } from \"./config.js\";\n\nexport function registerComponents(): void {\n if (!customElements.get(config.tagNames.pip)) {\n customElements.define(config.tagNames.pip, WcsPip);\n }\n}\n"],"names":["_config","tagNames","pip","deepFreeze","obj","Object","freeze","key","keys","deepClone","clone","frozenConfig","config","getConfig","PipCore","EventTarget","static","protocol","version","properties","name","event","getter","e","detail","active","commands","async","_target","_active","_error","_video","_gen","_ready","Promise","resolve","constructor","target","super","this","ready","error","observe","element","_detach","addEventListener","_onEnter","_onLeave","_syncActive","dispose","requestPictureInPicture","gen","tagName","_setError","message","fn","_requestPictureInPictureFn","call","exitPictureInPicture","_pictureInPictureElement","_exitPictureInPictureFn","el","undefined","d","document","bind","pictureInPictureElement","isActive","_setActive","removeEventListener","dispatchEvent","CustomEvent","bubbles","WcsPip","HTMLElement","wcBindable","inputs","attribute","_core","_connectedCallbackPromise","connectedCallbackPromise","getAttribute","value","setAttribute","_resolveVideoTarget","_resolveTarget","display","scope","getRootNode","_safeQuery","child","firstElementChild","selector","querySelector","_observe","style","connectedCallback","disconnectedCallback","attributeChangedCallback","_name","oldValue","newValue","isConnected","bootstrapPip","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/PipCore.ts","../src/components/Pip.ts","../src/bootstrapPip.ts","../src/registerComponents.ts"],"sourcesContent":["import { IConfig, IWritableConfig } from \"./types.js\";\n\ninterface IInternalConfig extends IConfig {\n tagNames: {\n pip: string;\n };\n}\n\nconst _config: IInternalConfig = {\n tagNames: {\n pip: \"wcs-pip\",\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 } from \"../types.js\";\n\n/**\n * Headless Picture-in-Picture primitive. A thin, framework-agnostic wrapper\n * around the classic Picture-in-Picture API\n * (`HTMLVideoElement.requestPictureInPicture()` / `document.exitPictureInPicture()` /\n * `document.pictureInPictureElement`) exposed through the wc-bindable protocol.\n *\n * This Core follows the same basic pattern as `@wcstack/fullscreen`'s\n * `FullscreenCore` (docs/fullscreen-tag-design.md): target resolution is done\n * by the Shell (this Core receives the resolved element at call time), API\n * resolution is call-time/non-cached, `_gen` is a single Core-level generation\n * guard, and `error` is a simple single field (no permission-style 4-value\n * state). See docs/picture-in-picture-tag-design.md for the differences from\n * Fullscreen:\n *\n * - **§2 target constraint**: the resolved target MUST be a `<video>` element.\n * Picture-in-Picture is only defined as an instance method of\n * `HTMLVideoElement` — unlike Fullscreen, which any `Element` supports. A\n * non-`<video>` target is a never-throw failure: it is treated the same as\n * an unresolved target and reported via `error`.\n * - **§3 event subscription target**: `enterpictureinpicture` /\n * `leavepictureinpicture` fire on the `<video>` element itself, not on\n * `document` (the reverse of Fullscreen's `document`-level\n * `fullscreenchange`). The Core attaches/detaches these listeners directly\n * on the resolved `<video>` element, re-wiring them whenever the target is\n * re-resolved (e.g. the Shell's `target` attribute changes).\n */\nexport class PipCore extends EventTarget {\n static wcBindable: IWcBindable = {\n protocol: \"wc-bindable\",\n version: 1,\n properties: [\n { name: \"active\", event: \"wcs-pip:change\", getter: (e: Event) => (e as CustomEvent).detail.active },\n ],\n commands: [\n { name: \"requestPictureInPicture\", async: true },\n { name: \"exitPictureInPicture\", async: true },\n ],\n };\n\n private _target: EventTarget;\n private _active: boolean = false;\n private _error: any = null;\n\n // The <video> element the Core currently subscribes to for\n // enterpictureinpicture/leavepictureinpicture (null when unresolved/torn down).\n private _video: HTMLVideoElement | null = null;\n\n // Generation guard (§3.4 / fullscreen-tag-design.md §6): bumped on dispose()\n // and each async command start. A completion that lands after dispose() (or\n // after a superseding call) is stale and MUST NOT write state.\n private _gen = 0;\n\n // SSR (§3.8): no asynchronous probe to await, so readiness is immediate.\n private _ready: Promise<void> = Promise.resolve();\n\n constructor(target?: EventTarget) {\n super();\n this._target = target ?? this;\n }\n\n get ready(): Promise<void> {\n return this._ready;\n }\n\n get active(): boolean {\n return this._active;\n }\n\n get error(): any {\n return this._error;\n }\n\n // --- Lifecycle (§3.5) ---\n\n /**\n * (Re-)subscribe to `enterpictureinpicture`/`leavepictureinpicture` on\n * `element` (the Shell's resolved `<video>` target). Idempotent when called\n * again with the same element; re-wires the listeners when the element\n * changes (e.g. the `target` attribute was changed), detaching from the\n * previous element first so no stale listener lingers.\n */\n observe(element: HTMLVideoElement | null): Promise<void> {\n if (this._video === element) {\n return this._ready;\n }\n this._detach();\n this._video = element;\n if (element) {\n element.addEventListener(\"enterpictureinpicture\", this._onEnter);\n element.addEventListener(\"leavepictureinpicture\", this._onLeave);\n }\n this._syncActive();\n return this._ready;\n }\n\n dispose(): void {\n this._gen++;\n this._detach();\n this._video = null;\n }\n\n // --- Commands (§3.6 never-throw) ---\n\n /**\n * Request Picture-in-Picture for `element`. `element` must be a `<video>`\n * (checked before the gesture-context failure path, since a type mismatch is\n * an environment-independent, permanent error — docs/picture-in-picture-tag-design.md §2).\n * Never throws: all failures (wrong tag, unsupported API, gesture-context\n * rejection) are funneled into `error` and the returned promise resolves.\n */\n async requestPictureInPicture(element: HTMLVideoElement | null): Promise<void> {\n const gen = ++this._gen;\n if (!element || element.tagName !== \"VIDEO\") {\n this._setError({ message: \"target must be a <video> element.\" });\n return;\n }\n // Re-wire to `element` before issuing the platform call: a caller may\n // request a <video> different from the one last passed to observe() (e.g.\n // the Shell's target attribute pointed at nothing at connect time and the\n // matching <video> was only inserted later, so no attributeChangedCallback\n // ever re-resolved it). Without this, `_video` stays stale and\n // `_syncActive()` below (and future enter/leave events) would never\n // recognize `element` as this Core's target, leaving `active` permanently\n // wrong even though the request succeeded (mirrors\n // FullscreenCore.requestFullscreen()'s unconditional `this._resolvedTarget\n // = element` assignment — docs/fullscreen-tag-design.md §6).\n this.observe(element);\n const fn = this._requestPictureInPictureFn(element);\n if (!fn) {\n this._setError({ message: \"Picture-in-Picture API is not supported.\" });\n return;\n }\n try {\n await fn.call(element);\n if (gen !== this._gen) return; // stale\n this._setError(null);\n this._syncActive(); // belt-and-suspenders (mirrors FullscreenCore's _applyActive() on success)\n } catch (e: any) {\n if (gen !== this._gen) return; // stale\n this._setError(e); // e.g. NotAllowedError (gesture-context rejection)\n }\n }\n\n /**\n * Exit Picture-in-Picture. Mirrors FullscreenCore.exitFullscreen(): a\n * silent no-op (resolve, no error) when nothing is currently in\n * Picture-in-Picture — see fullscreen-tag-design.md §7.\n */\n async exitPictureInPicture(): Promise<void> {\n // no-op checks come BEFORE the generation bump: a call that does nothing\n // must not supersede an in-flight requestPictureInPicture() — bumping\n // first would make the pending request's settle handling stale and\n // silently swallow its error update (mirrors\n // FullscreenCore.exitFullscreen()).\n if (this._pictureInPictureElement() === null) return; // already not in PiP: silent no-op\n const fn = this._exitPictureInPictureFn();\n if (!fn) return; // unsupported: silent no-op (semantically already \"not in PiP\")\n const gen = ++this._gen;\n try {\n await fn();\n if (gen !== this._gen) return;\n this._setError(null);\n this._syncActive(); // belt-and-suspenders (mirrors FullscreenCore.exitFullscreen()'s success-path _applyActive()); covers a delayed/dropped leavepictureinpicture\n } catch (e: any) {\n if (gen !== this._gen) return;\n this._setError(e);\n }\n }\n\n // --- Internal: API resolution (call-time, never cached — §3.7) ---\n\n // Unlike FullscreenCore's _elementFullscreenFn(), a naive direct property\n // lookup (`e.requestPictureInPicture`, walking the prototype chain) here is\n // safe: it cannot recurse into the Shell's own command method,\n // because the resolved target is validated to be a <video> element (§2)\n // before this is called, and <wcs-pip> (the Shell) is never itself a\n // <video>. Fullscreen's own→Element.prototype two-step resolution guards\n // against `target=\"self\"`/no-target resolving to the Shell element, which\n // cannot happen here.\n private _requestPictureInPictureFn(el: HTMLVideoElement): (() => Promise<PictureInPictureWindow>) | undefined {\n const e = el as any;\n return typeof e.requestPictureInPicture === \"function\" ? e.requestPictureInPicture : undefined;\n }\n\n private _exitPictureInPictureFn(): (() => Promise<void>) | undefined {\n const d = document as any;\n return typeof d.exitPictureInPicture === \"function\" ? d.exitPictureInPicture.bind(document) : undefined;\n }\n\n private _pictureInPictureElement(): Element | null {\n const d = document as any;\n return d.pictureInPictureElement ?? null;\n }\n\n // --- Internal: event wiring ---\n\n private _onEnter = (): void => {\n this._syncActive();\n };\n\n private _onLeave = (): void => {\n this._syncActive();\n };\n\n private _syncActive(): void {\n const isActive = this._video !== null && this._pictureInPictureElement() === this._video;\n this._setActive(isActive);\n }\n\n private _detach(): void {\n if (this._video) {\n this._video.removeEventListener(\"enterpictureinpicture\", this._onEnter);\n this._video.removeEventListener(\"leavepictureinpicture\", this._onLeave);\n }\n }\n\n // --- State setters with event dispatch (§3.3 same-value guard) ---\n\n private _setActive(active: boolean): void {\n if (this._active === active) return;\n this._active = active;\n this._target.dispatchEvent(new CustomEvent(\"wcs-pip:change\", {\n detail: { active },\n bubbles: true,\n }));\n }\n\n private _setError(error: any): void {\n this._error = error;\n }\n}\n","import { IWcBindable } from \"../types.js\";\nimport { PipCore } from \"../core/PipCore.js\";\n\n/**\n * `<wcs-pip target=\"...\">` — declarative Picture-in-Picture control.\n *\n * Like `<wcs-fullscreen>` (docs/fullscreen-tag-design.md §0/§1), this Shell\n * does not operate on itself: it is a non-visible control tag that resolves a\n * `target` element and invokes Picture-in-Picture commands against it. The\n * `target` attribute resolves in the same 3 modes as `intersection`/`fullscreen`\n * (`self` / a selector / the first element child), reused verbatim from\n * `@wcstack/intersection`'s `_resolveTarget()`/`_safeQuery()`\n * (packages/intersection/src/components/Intersect.ts).\n *\n * Picture-in-Picture-specific difference (docs/picture-in-picture-tag-design.md\n * §2): the resolved target must be a `<video>` element. This Shell resolves the\n * DOM element and hands it to the Core; the Core performs the `tagName ===\n * \"VIDEO\"` validation (never-throw — a mismatch is treated as an unresolved\n * target and reported via `error`, not thrown).\n */\nexport class WcsPip extends HTMLElement {\n // SSR (§4.4): observe() completes synchronously, but the Shell still exposes\n // connectedCallbackPromise so the state binder can await it uniformly across\n // all IO nodes before snapshotting.\n static hasConnectedCallbackPromise = true;\n\n static observedAttributes = [\"target\"];\n\n static wcBindable: IWcBindable = {\n ...PipCore.wcBindable,\n inputs: [{ name: \"target\", attribute: \"target\" }],\n // Core の commands をそのまま継承(単一情報源)。fullscreen/intersection と同型。\n commands: PipCore.wcBindable.commands,\n };\n\n private _core: PipCore;\n private _connectedCallbackPromise: Promise<void> = Promise.resolve();\n private _internals: ElementInternals | null = null;\n\n constructor() {\n super();\n this._core = new PipCore(this);\n this._internals = this._initInternals();\n this._wireStates({\n \"wcs-pip:change\": (d) => ({ active: d?.active === true }),\n });\n }\n\n // CSS state reflection (:state()) — debug-only snapshot getter. NOT part of\n // wc-bindable (not a bind target); see README \"CSS styling with :state()\".\n // MUST NOT return the live CustomStateSet (that would let callers write\n // states from outside, defeating the point of :state() being read-only).\n get debugStates(): string[] {\n return this._internals ? [...this._internals.states] : [];\n }\n\n private _initInternals(): ElementInternals | null {\n // never-throw (docs/custom-state-reflection-design.md §3.1): attachInternals\n // is absent in happy-dom / older environments, and pre-125 Chromium rejects\n // non-dashed state names from states.add() (probed and discarded here).\n // Either case silently disables reflection — the component still works,\n // it just doesn't expose :state() selectors.\n try {\n if (typeof this.attachInternals !== \"function\") return null;\n const internals = this.attachInternals();\n internals.states.add(\"wcs-probe\");\n internals.states.delete(\"wcs-probe\");\n return internals;\n } catch {\n return null;\n }\n }\n\n private _wireStates(map: Record<string, (detail: any) => Record<string, boolean>>): void {\n if (this._internals === null) return;\n const states = this._internals.states;\n for (const [event, toStates] of Object.entries(map)) {\n this.addEventListener(event, (e) => {\n const debug = this.hasAttribute(\"debug-states\");\n for (const [name, on] of Object.entries(toStates((e as CustomEvent).detail))) {\n try {\n if (on) { states.add(name); } else { states.delete(name); }\n } catch { /* never-throw */ }\n if (debug) this.toggleAttribute(`data-wcs-state-${name}`, on);\n }\n });\n }\n }\n\n get connectedCallbackPromise(): Promise<void> {\n return this._connectedCallbackPromise;\n }\n\n // --- Attribute accessors ---\n\n get target(): string {\n return this.getAttribute(\"target\") ?? \"\";\n }\n\n set target(value: string) {\n this.setAttribute(\"target\", value);\n }\n\n // --- Core delegated getters ---\n\n get active(): boolean {\n return this._core.active;\n }\n\n get error(): any {\n return this._core.error;\n }\n\n // --- Commands ---\n\n async requestPictureInPicture(): Promise<void> {\n const { element } = this._resolveVideoTarget();\n return this._core.requestPictureInPicture(element);\n }\n\n async exitPictureInPicture(): Promise<void> {\n return this._core.exitPictureInPicture();\n }\n\n // --- Internal ---\n\n /**\n * `_resolveTarget()`/`_safeQuery()` copied verbatim from `@wcstack/intersection`\n * (packages/intersection/src/components/Intersect.ts:243-267, 281-287) per the\n * fullscreen/picture-in-picture batch's shared target-resolution archetype\n * (docs/fullscreen-tag-design.md §1).\n */\n private _resolveTarget(): { element: Element | null; display: string } {\n const target = this.target;\n if (target === \"self\") {\n return { element: this, display: \"block\" };\n }\n if (target !== \"\") {\n const scope = this.getRootNode() as Document | ShadowRoot;\n return { element: this._safeQuery(scope, target), display: \"none\" };\n }\n const child = this.firstElementChild;\n if (child) {\n return { element: child, display: \"contents\" };\n }\n return { element: this, display: \"block\" };\n }\n\n private _safeQuery(scope: Document | ShadowRoot, selector: string): Element | null {\n try {\n return scope.querySelector(selector);\n } catch {\n return null;\n }\n }\n\n /**\n * Layers the Picture-in-Picture-specific `tagName === \"VIDEO\"` check on top\n * of `_resolveTarget()` (docs/picture-in-picture-tag-design.md §2). A\n * resolved-but-wrong-tag element is treated as unresolved (`element: null`)\n * so it flows into the same \"target not found\" failure path as Fullscreen's\n * missing-target case — never-throw, no exception escapes.\n */\n private _resolveVideoTarget(): { element: HTMLVideoElement | null; display: string } {\n const { element, display } = this._resolveTarget();\n if (element !== null && element.tagName !== \"VIDEO\") {\n return { element: null, display };\n }\n return { element: element as HTMLVideoElement | null, display };\n }\n\n private _observe(): void {\n const { element, display } = this._resolveVideoTarget();\n this.style.display = display;\n this._connectedCallbackPromise = this._core.observe(element);\n }\n\n // --- Lifecycle ---\n\n connectedCallback(): void {\n this._observe();\n }\n\n disconnectedCallback(): void {\n this._core.dispose();\n }\n\n attributeChangedCallback(_name: string, oldValue: string | null, newValue: string | null): void {\n if (oldValue === newValue) return;\n if (!this.isConnected) return;\n this._observe();\n }\n}\n","import { setConfig } from \"./config.js\";\nimport { registerComponents } from \"./registerComponents.js\";\nimport { IWritableConfig } from \"./types.js\";\n\nexport function bootstrapPip(userConfig?: IWritableConfig): void {\n if (userConfig) {\n setConfig(userConfig);\n }\n registerComponents();\n}\n","import { WcsPip } from \"./components/Pip.js\";\nimport { config } from \"./config.js\";\n\nexport function registerComponents(): void {\n if (!customElements.get(config.tagNames.pip)) {\n customElements.define(config.tagNames.pip, WcsPip);\n }\n}\n"],"names":["_config","tagNames","pip","deepFreeze","obj","Object","freeze","key","keys","deepClone","clone","frozenConfig","config","getConfig","PipCore","EventTarget","static","protocol","version","properties","name","event","getter","e","detail","active","commands","async","_target","_active","_error","_video","_gen","_ready","Promise","resolve","constructor","target","super","this","ready","error","observe","element","_detach","addEventListener","_onEnter","_onLeave","_syncActive","dispose","requestPictureInPicture","gen","tagName","_setError","message","fn","_requestPictureInPictureFn","call","exitPictureInPicture","_pictureInPictureElement","_exitPictureInPictureFn","el","undefined","d","document","bind","pictureInPictureElement","isActive","_setActive","removeEventListener","dispatchEvent","CustomEvent","bubbles","WcsPip","HTMLElement","wcBindable","inputs","attribute","_core","_connectedCallbackPromise","_internals","_initInternals","_wireStates","debugStates","states","attachInternals","internals","add","delete","map","toStates","entries","debug","hasAttribute","on","toggleAttribute","connectedCallbackPromise","getAttribute","value","setAttribute","_resolveVideoTarget","_resolveTarget","display","scope","getRootNode","_safeQuery","child","firstElementChild","selector","querySelector","_observe","style","connectedCallback","disconnectedCallback","attributeChangedCallback","_name","oldValue","newValue","isConnected","bootstrapPip","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/picture-in-picture",
3
- "version": "1.16.0",
3
+ "version": "1.17.0",
4
4
  "description": "Declarative Picture-in-Picture component for Web Components. Framework-agnostic <video> Picture-in-Picture control via wc-bindable-protocol.",
5
5
  "type": "module",
6
6
  "main": "./dist/index.esm.js",