@wcstack/fullscreen 1.16.0 → 1.18.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.ja.md CHANGED
@@ -96,6 +96,57 @@ npm install @wcstack/fullscreen
96
96
  | ---------- | ---- |
97
97
  | `target` | `@wcstack/intersection` の `target` と同じ3モード解決: `"self"`、CSSセレクタ、または省略(最初の子要素)。 |
98
98
 
99
+ ## `:state()` による CSS スタイリング
100
+
101
+ `<wcs-fullscreen>` は 1 つの boolean 出力ステートを
102
+ [`ElementInternals` の `CustomStateSet`](https://developer.mozilla.org/ja/docs/Web/API/CustomStateSet)
103
+ に反映します。そのため `data-wcs` バインディングやクラスの手動トグルなしに、CSS の
104
+ `:state()` 疑似クラスで直接スタイリングできます。
105
+
106
+ | ステート | on になる条件 |
107
+ |----------|----------------|
108
+ | `active` | `wcs-fullscreen:change` が `detail.active === true` で発火(`active: false` でクリア) |
109
+
110
+ `error` は反映**しません**: 専用イベントを持たず、`static wcBindable.properties`
111
+ にも宣言されていないため(上記「注意・制限」参照)、`:state()` 反映が購読できる対象がありません。
112
+
113
+ ```css
114
+ wcs-fullscreen:state(active) ~ .exit-hint { display: block; }
115
+ wcs-fullscreen:state(active) ~ .exit-hint { display: none; } /* デフォルト */
116
+ ```
117
+
118
+ 属性やクラスと異なり `:state()` は要素の外部から書き込めないため、この出力ステートが
119
+ 入力と混同される心配がありません。
120
+
121
+ **対応ブラウザ**(新構文 `:state(x)`): Chrome/Edge 125+、Safari 17.4+、Firefox 126+。
122
+ 非対応の環境ではステートが一切 set されないだけです — `:state()` セレクタがマッチしなく
123
+ なりますが、`<wcs-fullscreen>` 自体は通常どおり動作し続けます(graceful degradation・never-throw)。
124
+
125
+ **SSR:** `:state()` は HTML にシリアライズできないため、サーバーレンダリングされた
126
+ マークアップの初期ペイントにはこれらのステートは乗りません(`@wcstack/server` は無改変)。
127
+ ハイドレーション前の見た目を制御したい場合は、代わりに `wcs-fullscreen:not(:defined)` と組み合わせてください。
128
+
129
+ ### デバッグ
130
+
131
+ カスタムステートは DevTools の Elements パネルには表示されず、`attachInternals()`
132
+ は同一要素に 2 回呼べないため、コンソールから直接覗く手段がありません。そのための
133
+ デバッグ専用の補助を 2 つ用意しています:
134
+
135
+ - `el.debugStates` — 現在 on になっているステート名の**スナップショット**配列
136
+ (例: `["active"]`)。`wc-bindable` の一部ではなく(バインド対象ではない)、
137
+ 形状も契約として保証されません — デバッグ用途にのみ使ってください。
138
+ - `debug-states` 属性(opt-in・既定 OFF)は、ステート変化を要素の
139
+ `data-wcs-state-active` 属性にミラーします。
140
+ Elements パネルを開いておけば、トグルのたびにハイライトされます:
141
+
142
+ ```html
143
+ <wcs-fullscreen target="#hero" debug-states></wcs-fullscreen>
144
+ ```
145
+
146
+ **CSS は `data-wcs-state-*` ではなく `:state()` に書いてください。** ミラーされた
147
+ 属性は、DevTools を開いた状態でステート変化を可視化するためだけのものであり、
148
+ スタイリング用の正式なフックではありません。
149
+
99
150
  ## 注意・制限
100
151
 
101
152
  - **user gesture制約。** `requestFullscreen()` は実際のuser gesture(クリックハンドラ等)内から同期的に呼ばれた場合のみ成功します。本ノードはgestureを生成できません — command-tokenプロトコル経由(`<wcs-fullscreen>` 側の `command.requestFullscreen: $command.<token>`、ボタン側の `onclick: $command.<token>`)で呼び出す場合は、**起動元のイベント自体**が本物のuser gestureであることを確認してください。`setTimeout` の中やPromiseチェーンの奥深くから呼び出すと、呼び出し方法に関わらず `TypeError`(WHATWG Fullscreen仕様のtransient-activationチェックによる。`NotAllowedError` ではない)でrejectされます — これはブラウザレベルの制約であり、wcstack側で回避する手段はありません。
package/README.md CHANGED
@@ -96,6 +96,60 @@ Every bound state path must be declared up front — `isFullscreen: false` here;
96
96
  | ---------- | ------------ |
97
97
  | `target` | Same 3-mode resolution as `@wcstack/intersection`'s `target`: `"self"`, a CSS selector, or omitted (first child). |
98
98
 
99
+ ## CSS styling with `:state()`
100
+
101
+ `<wcs-fullscreen>` reflects one boolean output state onto its
102
+ [`ElementInternals` `CustomStateSet`](https://developer.mozilla.org/en-US/docs/Web/API/CustomStateSet),
103
+ so you can style it directly from CSS with the `:state()` pseudo-class — no
104
+ `data-wcs` binding or extra class toggling required.
105
+
106
+ | State | On when |
107
+ |-------|---------|
108
+ | `active` | `wcs-fullscreen:change` fires with `detail.active === true` (cleared when `active: false`) |
109
+
110
+ `error` is **not** reflected: it has no dedicated event and is not declared in
111
+ `static wcBindable.properties` (see "Notes & limitations" above), so there is
112
+ nothing for `:state()` reflection to subscribe to.
113
+
114
+ ```css
115
+ wcs-fullscreen:state(active) ~ .exit-hint { display: block; }
116
+ wcs-fullscreen:state(active) ~ .exit-hint { display: none; } /* default */
117
+ ```
118
+
119
+ Unlike attributes or classes, `:state()` cannot be written from outside the
120
+ element, so there is no risk of confusing this output state with an input.
121
+
122
+ **Browser support** (`:state(x)` syntax): Chrome/Edge 125+, Safari 17.4+,
123
+ Firefox 126+. In older browsers the states are simply never set — `:state()`
124
+ selectors never match, but `<wcs-fullscreen>` itself keeps working normally
125
+ (graceful degradation, never-throw).
126
+
127
+ **SSR**: `:state()` cannot be serialized into HTML, so server-rendered markup
128
+ never carries these states on first paint (`@wcstack/server` is unaffected).
129
+ If you need to style the pre-hydration gap, pair your rule with
130
+ `wcs-fullscreen:not(:defined)` instead.
131
+
132
+ ### Debugging
133
+
134
+ Custom states are invisible in DevTools' Elements panel and `attachInternals()`
135
+ cannot be called twice, so there is no console way to inspect them directly.
136
+ Two debug-only aids are provided for that:
137
+
138
+ - `el.debugStates` — a **snapshot** array of the currently-on state names
139
+ (e.g. `["active"]`). It is not part of `wc-bindable` (not a bind target)
140
+ and its shape is not a guaranteed contract — use it for debugging only.
141
+ - The `debug-states` attribute (opt-in, default off) mirrors state changes
142
+ onto a `data-wcs-state-active` attribute on the element, so the Elements
143
+ panel highlights it as it toggles:
144
+
145
+ ```html
146
+ <wcs-fullscreen target="#hero" debug-states></wcs-fullscreen>
147
+ ```
148
+
149
+ **Write your CSS against `:state()`, not `data-wcs-state-*`.** The mirrored
150
+ attribute exists purely to make state changes visible while debugging with
151
+ DevTools open; it is not a supported styling hook.
152
+
99
153
  ## Notes & limitations
100
154
 
101
155
  - **User gesture requirement.** `requestFullscreen()` only succeeds when called synchronously from within a real user gesture (e.g. a click handler). This node cannot manufacture a gesture — if you invoke `requestFullscreen` via the command-token protocol (`command.requestFullscreen: $command.<token>` on `<wcs-fullscreen>`, emitted by a button's `onclick: $command.<token>`), make sure the *triggering* event itself is a genuine user gesture. Calling it from inside a `setTimeout` or deep in a promise chain will reject with a `TypeError` (per the WHATWG Fullscreen spec's transient-activation check — not `NotAllowedError`) regardless of how it was invoked — this is a browser-level constraint, not something wcstack can work around.
package/dist/index.d.ts CHANGED
@@ -155,7 +155,11 @@ declare class WcsFullscreen extends HTMLElement {
155
155
  static wcBindable: IWcBindable;
156
156
  private _core;
157
157
  private _connectedCallbackPromise;
158
+ private _internals;
158
159
  constructor();
160
+ get debugStates(): string[];
161
+ private _initInternals;
162
+ private _wireStates;
159
163
  get connectedCallbackPromise(): Promise<void>;
160
164
  get target(): string;
161
165
  set target(value: string);
package/dist/index.esm.js CHANGED
@@ -292,9 +292,62 @@ class WcsFullscreen extends HTMLElement {
292
292
  };
293
293
  _core;
294
294
  _connectedCallbackPromise = Promise.resolve();
295
+ _internals = null;
295
296
  constructor() {
296
297
  super();
297
298
  this._core = new FullscreenCore(this);
299
+ this._internals = this._initInternals();
300
+ this._wireStates({
301
+ "wcs-fullscreen:change": (d) => ({ active: d?.active === true }),
302
+ });
303
+ }
304
+ // CSS state reflection (:state()) — debug-only snapshot getter. NOT part of
305
+ // wc-bindable (not a bind target); see README "CSS styling with :state()".
306
+ // MUST NOT return the live CustomStateSet (that would let callers write
307
+ // states from outside, defeating the point of :state() being read-only).
308
+ get debugStates() {
309
+ return this._internals ? [...this._internals.states] : [];
310
+ }
311
+ _initInternals() {
312
+ // never-throw (docs/custom-state-reflection-design.md §3.1): attachInternals
313
+ // is absent in happy-dom / older environments, and pre-125 Chromium rejects
314
+ // non-dashed state names from states.add() (probed and discarded here).
315
+ // Either case silently disables reflection — the component still works,
316
+ // it just doesn't expose :state() selectors.
317
+ try {
318
+ if (typeof this.attachInternals !== "function")
319
+ return null;
320
+ const internals = this.attachInternals();
321
+ internals.states.add("wcs-probe");
322
+ internals.states.delete("wcs-probe");
323
+ return internals;
324
+ }
325
+ catch {
326
+ return null;
327
+ }
328
+ }
329
+ _wireStates(map) {
330
+ if (this._internals === null)
331
+ return;
332
+ const states = this._internals.states;
333
+ for (const [event, toStates] of Object.entries(map)) {
334
+ this.addEventListener(event, (e) => {
335
+ const debug = this.hasAttribute("debug-states");
336
+ for (const [name, on] of Object.entries(toStates(e.detail))) {
337
+ try {
338
+ if (on) {
339
+ states.add(name);
340
+ }
341
+ else {
342
+ states.delete(name);
343
+ }
344
+ }
345
+ catch { /* never-throw */ }
346
+ if (debug)
347
+ this.toggleAttribute(`data-wcs-state-${name}`, on);
348
+ }
349
+ });
350
+ }
298
351
  }
299
352
  get connectedCallbackPromise() {
300
353
  return this._connectedCallbackPromise;
@@ -1 +1 @@
1
- {"version":3,"file":"index.esm.js","sources":["../src/config.ts","../src/core/FullscreenCore.ts","../src/components/Fullscreen.ts","../src/registerComponents.ts","../src/bootstrapFullscreen.ts"],"sourcesContent":["import { IConfig, IWritableConfig } from \"./types.js\";\n\ninterface IInternalConfig extends IConfig {\n tagNames: {\n fullscreen: string;\n };\n}\n\nconst _config: IInternalConfig = {\n tagNames: {\n fullscreen: \"wcs-fullscreen\",\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 Fullscreen API primitive. Unlike most wcstack IO nodes, this Core\n * does not operate on itself: it drives `requestFullscreen()` /\n * `exitFullscreen()` on a *referenced* Element that the Shell resolves via its\n * `target` attribute (docs/fullscreen-tag-design.md §0). The Core only ever\n * receives already-resolved `Element`s from its callers — it has no opinion on\n * how `target` selectors are parsed.\n *\n * `document.fullscreenElement` is a single document-wide value, so this Core\n * always compares against the *last element it resolved* (via\n * `requestFullscreen()`/`setTarget()`), never against \"is the document\n * fullscreen at all\" — that comparison is what keeps multiple concurrent\n * `<wcs-fullscreen>` instances from all reporting the same `active` value\n * (docs/fullscreen-tag-design.md §2.1, MUST).\n */\nexport class FullscreenCore extends EventTarget {\n static wcBindable: IWcBindable = {\n protocol: \"wc-bindable\",\n version: 1,\n properties: [\n { name: \"active\", event: \"wcs-fullscreen:change\", getter: (e: Event) => (e as CustomEvent).detail.active },\n ],\n commands: [\n { name: \"requestFullscreen\", async: true },\n { name: \"exitFullscreen\", async: true },\n ],\n };\n\n private _target: EventTarget;\n private _active: boolean = false;\n // Single error slot (§8): null means \"no recent failure\". Fullscreen's\n // gesture-rejection failure is a one-shot event, not a persistent state\n // machine like permission's 4-value surface — active/error are two\n // orthogonal, independently-observable axes.\n private _error: any = null;\n\n // The last Element this Core resolved via requestFullscreen()/setTarget().\n // Compared against document.fullscreenElement on every fullscreenchange so\n // each instance judges only its own target (§2.1). null means \"no target\n // resolved yet\" — active must stay false in that case.\n private _resolvedTarget: Element | null = null;\n\n // Generation guard (§6): Core-scoped (one per Core, not per-target),\n // mirroring fetch/upload. document.fullscreenElement is a single\n // document-wide slot, so at most one in-flight request/exit is meaningful\n // per Core at a time.\n private _gen = 0;\n\n // True once observe() has attached the document-level fullscreenchange\n // listener. Guards observe() so a redundant call does not double-subscribe;\n // dispose() resets it so a later observe() resumes cleanly.\n private _subscribed = false;\n\n // SSR (§10): no asynchronous probe to await — observe() completes\n // synchronously, 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 /**\n * Update the resolved target without issuing a fullscreen request (e.g. the\n * Shell re-resolves `target` on attribute change / connect). Re-evaluates\n * `active` against the current `document.fullscreenElement` so the state\n * stays correct even if the target changed while already fullscreen.\n */\n setTarget(element: Element | null): void {\n this._resolvedTarget = element;\n this._applyActive();\n }\n\n // Lifecycle (§10/§3.5). Idempotent: a second observe() while already\n // subscribed is a no-op (no double listener). Synchronous overall (no probe\n // to await), so the returned promise is only for API uniformity with other\n // IO nodes.\n observe(): Promise<void> {\n if (!this._subscribed) {\n this._subscribed = true;\n document.addEventListener(this._fullscreenChangeEventName(), this._onFullscreenChange);\n }\n return this._ready;\n }\n\n dispose(): void {\n this._gen++;\n if (this._subscribed) {\n this._subscribed = false;\n document.removeEventListener(this._fullscreenChangeEventName(), this._onFullscreenChange);\n }\n }\n\n /**\n * Request fullscreen on `element`. never-throw (§3/§6): a missing API or a\n * rejected promise (e.g. a `TypeError` from a call outside a user\n * gesture, per the WHATWG Fullscreen spec's transient-activation check) is\n * caught and surfaced via `error`, never thrown. The caller\n * (Shell) is responsible for resolving `target` and for ensuring this is\n * invoked from within an actual user gesture — this Core cannot manufacture\n * one (docs/fullscreen-tag-design.md §3).\n */\n async requestFullscreen(element: Element | null): Promise<void> {\n const gen = ++this._gen;\n this._resolvedTarget = element;\n if (!element) {\n // Distinct from \"API is not supported\" (below): the Shell's `target`\n // selector did not resolve to any element (missing/typo'd selector).\n // Conflating the two previously misled users into thinking Fullscreen\n // itself was unsupported when only their selector was wrong.\n this._setError({ message: \"Fullscreen target could not be resolved.\" });\n return;\n }\n const fn = this._requestFullscreenFn(element);\n if (!fn) {\n this._setError({ message: \"Fullscreen API is not supported.\" });\n return;\n }\n try {\n await fn.call(element);\n if (gen !== this._gen) return; // stale: dispose()/superseding call ran\n this._setError(null);\n this._applyActive();\n } catch (e: any) {\n if (gen !== this._gen) return; // stale\n this._setError(e);\n }\n }\n\n /**\n * Exit fullscreen. Silent no-op (§7) when nothing is currently fullscreen or\n * the API is unsupported — both are treated as \"already achieved the exit\n * intent\", not as errors, keeping repeated calls safe and never-throw.\n */\n async exitFullscreen(): Promise<void> {\n // no-op checks come BEFORE the generation bump: a call that does nothing\n // must not supersede an in-flight requestFullscreen() — bumping first\n // would make the pending request's settle handling stale and silently\n // swallow its error/active updates.\n if (this._fullscreenElement() === null) return; // already not fullscreen: silent no-op\n const fn = this._exitFullscreenFn();\n if (!fn) return; // unsupported: silent no-op (semantically already \"not fullscreen\")\n const gen = ++this._gen;\n try {\n await fn();\n if (gen !== this._gen) return; // stale\n this._setError(null);\n this._applyActive();\n } catch (e: any) {\n if (gen !== this._gen) return; // stale\n this._setError(e);\n }\n }\n\n // --- API resolution layer (§4): call-time, never cached. Lets tests\n // install/remove the standard/legacy APIs freely and lets an unsupported\n // environment be detected correctly on every call. ---\n\n private _requestFullscreenFn(el: Element): (() => Promise<void>) | undefined {\n return this._elementFullscreenFn(el, \"requestFullscreen\")\n ?? this._elementFullscreenFn(el, \"webkitRequestFullscreen\");\n }\n\n // Resolve a fullscreen method for `el` WITHOUT a naive `el[name]` lookup.\n // A plain lookup walks the whole prototype chain — and <wcs-fullscreen>\n // itself declares a `requestFullscreen()` *command* method, so when the\n // resolved target is the Shell element (target=\"self\", or target omitted\n // with no children), the naive lookup would find the Shell's own command\n // instead of the platform API and recurse infinitely (stack overflow).\n // Instead: check the element's own properties (how tests install stubs —\n // happy-dom has no Fullscreen API — and how a deliberate per-element\n // monkey-patch would appear), then jump straight to Element.prototype,\n // where the platform defines the real methods. Both the standard and the\n // legacy webkit name go through this same resolution for symmetry.\n private _elementFullscreenFn(el: Element, name: string): (() => Promise<void>) | undefined {\n if (Object.prototype.hasOwnProperty.call(el, name)) {\n return (el as any)[name];\n }\n return (Element.prototype as any)[name];\n }\n\n private _exitFullscreenFn(): (() => Promise<void>) | undefined {\n const d = document as any;\n return d.exitFullscreen?.bind(document) ?? d.webkitExitFullscreen?.bind(document);\n }\n\n private _fullscreenElement(): Element | null {\n const d = document as any;\n return d.fullscreenElement ?? d.webkitFullscreenElement ?? null;\n }\n\n private _fullscreenChangeEventName(): string {\n return \"onfullscreenchange\" in document ? \"fullscreenchange\" : \"webkitfullscreenchange\";\n }\n\n // --- Internal ---\n\n private _onFullscreenChange = (): void => {\n this._applyActive();\n };\n\n // Re-derive `active` by comparing document.fullscreenElement (incl. legacy\n // fallback) against *this instance's* resolved target (§2/§2.1/§5). A null\n // resolved target always yields active=false — there is nothing for this\n // instance to claim as \"mine\".\n private _applyActive(): void {\n const next = this._resolvedTarget !== null && this._fullscreenElement() === this._resolvedTarget;\n this._setActive(next);\n }\n\n private _setActive(v: boolean): void {\n if (this._active === v) return; // same-value guard (§3.3 MUST)\n this._active = v;\n this._target.dispatchEvent(new CustomEvent(\"wcs-fullscreen:change\", {\n detail: { active: v },\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 { FullscreenCore } from \"../core/FullscreenCore.js\";\n\n/**\n * `<wcs-fullscreen target=\"...\">` — declarative Fullscreen API control.\n *\n * Like `intersection`/`resize`, this Shell operates on a *referenced* element,\n * not itself (docs/fullscreen-tag-design.md §0): `target` resolves which\n * element `requestFullscreen()`/`exitFullscreen()` are invoked on, using the\n * exact same 3-mode resolution as `<wcs-intersect>`\n * (docs/fullscreen-tag-design.md §1):\n *\n * | `target` | operates on | display | use case |\n * |-----------------|-------------------------|-------------|--------------------------|\n * | omitted | first element child | `contents` | wrap a gallery image/video |\n * | `\"#hero\"` / sel | the matched element | `none` | point at a distant node |\n * | `\"self\"` | the element itself | `block` | fullscreen the wrapper |\n *\n * `requestFullscreen()` requires an active user gesture — this element cannot\n * manufacture one. Invoke the command from within a real click handler\n * (typically via the command-token protocol: this element subscribes with\n * `command.requestFullscreen: $command.<token>`, and a button emits the\n * token from its own click handler, e.g. `onclick: $command.<token>`).\n */\nexport class WcsFullscreen extends HTMLElement {\n // SSR (§10): the fullscreenchange subscription is established synchronously\n // on connect, but the Shell still exposes connectedCallbackPromise so the\n // state binder can await it uniformly across all IO nodes before\n // snapshotting.\n static hasConnectedCallbackPromise = true;\n\n static observedAttributes = [\"target\"];\n\n static wcBindable: IWcBindable = {\n ...FullscreenCore.wcBindable,\n inputs: [{ name: \"target\", attribute: \"target\" }],\n // Core の commands をそのまま継承(単一情報源)。network/intersection と同型。\n commands: FullscreenCore.wcBindable.commands,\n };\n\n private _core: FullscreenCore;\n private _connectedCallbackPromise: Promise<void> = Promise.resolve();\n\n constructor() {\n super();\n this._core = new FullscreenCore(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 /**\n * Resolve `target` and request fullscreen on it. never-throw: an\n * unresolvable target or an unsupported/rejected API call are both\n * surfaced via `error`, never thrown (docs/fullscreen-tag-design.md §3/§6).\n */\n async requestFullscreen(): Promise<void> {\n const { element } = this._resolveTarget();\n await this._core.requestFullscreen(element);\n }\n\n async exitFullscreen(): Promise<void> {\n await this._core.exitFullscreen();\n }\n\n // --- Internal ---\n\n // Copied verbatim from <wcs-intersect> (Intersect.ts _resolveTarget/_safeQuery,\n // docs/fullscreen-tag-design.md §1): identical 3-mode resolution, only the\n // \"what to do with the resolved element\" step differs.\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 private _reresolve(): void {\n const { element, display } = this._resolveTarget();\n this.style.display = display;\n this._core.setTarget(element);\n }\n\n // --- Lifecycle ---\n\n connectedCallback(): void {\n this._reresolve();\n this._connectedCallbackPromise = this._core.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._reresolve();\n }\n}\n","import { WcsFullscreen } from \"./components/Fullscreen.js\";\nimport { config } from \"./config.js\";\n\nexport function registerComponents(): void {\n if (!customElements.get(config.tagNames.fullscreen)) {\n customElements.define(config.tagNames.fullscreen, WcsFullscreen);\n }\n}\n","import { setConfig } from \"./config.js\";\nimport { registerComponents } from \"./registerComponents.js\";\nimport { IWritableConfig } from \"./types.js\";\n\nexport function bootstrapFullscreen(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/FullscreenCore.ts","../src/components/Fullscreen.ts","../src/registerComponents.ts","../src/bootstrapFullscreen.ts"],"sourcesContent":["import { IConfig, IWritableConfig } from \"./types.js\";\n\ninterface IInternalConfig extends IConfig {\n tagNames: {\n fullscreen: string;\n };\n}\n\nconst _config: IInternalConfig = {\n tagNames: {\n fullscreen: \"wcs-fullscreen\",\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 Fullscreen API primitive. Unlike most wcstack IO nodes, this Core\n * does not operate on itself: it drives `requestFullscreen()` /\n * `exitFullscreen()` on a *referenced* Element that the Shell resolves via its\n * `target` attribute (docs/fullscreen-tag-design.md §0). The Core only ever\n * receives already-resolved `Element`s from its callers — it has no opinion on\n * how `target` selectors are parsed.\n *\n * `document.fullscreenElement` is a single document-wide value, so this Core\n * always compares against the *last element it resolved* (via\n * `requestFullscreen()`/`setTarget()`), never against \"is the document\n * fullscreen at all\" — that comparison is what keeps multiple concurrent\n * `<wcs-fullscreen>` instances from all reporting the same `active` value\n * (docs/fullscreen-tag-design.md §2.1, MUST).\n */\nexport class FullscreenCore extends EventTarget {\n static wcBindable: IWcBindable = {\n protocol: \"wc-bindable\",\n version: 1,\n properties: [\n { name: \"active\", event: \"wcs-fullscreen:change\", getter: (e: Event) => (e as CustomEvent).detail.active },\n ],\n commands: [\n { name: \"requestFullscreen\", async: true },\n { name: \"exitFullscreen\", async: true },\n ],\n };\n\n private _target: EventTarget;\n private _active: boolean = false;\n // Single error slot (§8): null means \"no recent failure\". Fullscreen's\n // gesture-rejection failure is a one-shot event, not a persistent state\n // machine like permission's 4-value surface — active/error are two\n // orthogonal, independently-observable axes.\n private _error: any = null;\n\n // The last Element this Core resolved via requestFullscreen()/setTarget().\n // Compared against document.fullscreenElement on every fullscreenchange so\n // each instance judges only its own target (§2.1). null means \"no target\n // resolved yet\" — active must stay false in that case.\n private _resolvedTarget: Element | null = null;\n\n // Generation guard (§6): Core-scoped (one per Core, not per-target),\n // mirroring fetch/upload. document.fullscreenElement is a single\n // document-wide slot, so at most one in-flight request/exit is meaningful\n // per Core at a time.\n private _gen = 0;\n\n // True once observe() has attached the document-level fullscreenchange\n // listener. Guards observe() so a redundant call does not double-subscribe;\n // dispose() resets it so a later observe() resumes cleanly.\n private _subscribed = false;\n\n // SSR (§10): no asynchronous probe to await — observe() completes\n // synchronously, 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 /**\n * Update the resolved target without issuing a fullscreen request (e.g. the\n * Shell re-resolves `target` on attribute change / connect). Re-evaluates\n * `active` against the current `document.fullscreenElement` so the state\n * stays correct even if the target changed while already fullscreen.\n */\n setTarget(element: Element | null): void {\n this._resolvedTarget = element;\n this._applyActive();\n }\n\n // Lifecycle (§10/§3.5). Idempotent: a second observe() while already\n // subscribed is a no-op (no double listener). Synchronous overall (no probe\n // to await), so the returned promise is only for API uniformity with other\n // IO nodes.\n observe(): Promise<void> {\n if (!this._subscribed) {\n this._subscribed = true;\n document.addEventListener(this._fullscreenChangeEventName(), this._onFullscreenChange);\n }\n return this._ready;\n }\n\n dispose(): void {\n this._gen++;\n if (this._subscribed) {\n this._subscribed = false;\n document.removeEventListener(this._fullscreenChangeEventName(), this._onFullscreenChange);\n }\n }\n\n /**\n * Request fullscreen on `element`. never-throw (§3/§6): a missing API or a\n * rejected promise (e.g. a `TypeError` from a call outside a user\n * gesture, per the WHATWG Fullscreen spec's transient-activation check) is\n * caught and surfaced via `error`, never thrown. The caller\n * (Shell) is responsible for resolving `target` and for ensuring this is\n * invoked from within an actual user gesture — this Core cannot manufacture\n * one (docs/fullscreen-tag-design.md §3).\n */\n async requestFullscreen(element: Element | null): Promise<void> {\n const gen = ++this._gen;\n this._resolvedTarget = element;\n if (!element) {\n // Distinct from \"API is not supported\" (below): the Shell's `target`\n // selector did not resolve to any element (missing/typo'd selector).\n // Conflating the two previously misled users into thinking Fullscreen\n // itself was unsupported when only their selector was wrong.\n this._setError({ message: \"Fullscreen target could not be resolved.\" });\n return;\n }\n const fn = this._requestFullscreenFn(element);\n if (!fn) {\n this._setError({ message: \"Fullscreen API is not supported.\" });\n return;\n }\n try {\n await fn.call(element);\n if (gen !== this._gen) return; // stale: dispose()/superseding call ran\n this._setError(null);\n this._applyActive();\n } catch (e: any) {\n if (gen !== this._gen) return; // stale\n this._setError(e);\n }\n }\n\n /**\n * Exit fullscreen. Silent no-op (§7) when nothing is currently fullscreen or\n * the API is unsupported — both are treated as \"already achieved the exit\n * intent\", not as errors, keeping repeated calls safe and never-throw.\n */\n async exitFullscreen(): Promise<void> {\n // no-op checks come BEFORE the generation bump: a call that does nothing\n // must not supersede an in-flight requestFullscreen() — bumping first\n // would make the pending request's settle handling stale and silently\n // swallow its error/active updates.\n if (this._fullscreenElement() === null) return; // already not fullscreen: silent no-op\n const fn = this._exitFullscreenFn();\n if (!fn) return; // unsupported: silent no-op (semantically already \"not fullscreen\")\n const gen = ++this._gen;\n try {\n await fn();\n if (gen !== this._gen) return; // stale\n this._setError(null);\n this._applyActive();\n } catch (e: any) {\n if (gen !== this._gen) return; // stale\n this._setError(e);\n }\n }\n\n // --- API resolution layer (§4): call-time, never cached. Lets tests\n // install/remove the standard/legacy APIs freely and lets an unsupported\n // environment be detected correctly on every call. ---\n\n private _requestFullscreenFn(el: Element): (() => Promise<void>) | undefined {\n return this._elementFullscreenFn(el, \"requestFullscreen\")\n ?? this._elementFullscreenFn(el, \"webkitRequestFullscreen\");\n }\n\n // Resolve a fullscreen method for `el` WITHOUT a naive `el[name]` lookup.\n // A plain lookup walks the whole prototype chain — and <wcs-fullscreen>\n // itself declares a `requestFullscreen()` *command* method, so when the\n // resolved target is the Shell element (target=\"self\", or target omitted\n // with no children), the naive lookup would find the Shell's own command\n // instead of the platform API and recurse infinitely (stack overflow).\n // Instead: check the element's own properties (how tests install stubs —\n // happy-dom has no Fullscreen API — and how a deliberate per-element\n // monkey-patch would appear), then jump straight to Element.prototype,\n // where the platform defines the real methods. Both the standard and the\n // legacy webkit name go through this same resolution for symmetry.\n private _elementFullscreenFn(el: Element, name: string): (() => Promise<void>) | undefined {\n if (Object.prototype.hasOwnProperty.call(el, name)) {\n return (el as any)[name];\n }\n return (Element.prototype as any)[name];\n }\n\n private _exitFullscreenFn(): (() => Promise<void>) | undefined {\n const d = document as any;\n return d.exitFullscreen?.bind(document) ?? d.webkitExitFullscreen?.bind(document);\n }\n\n private _fullscreenElement(): Element | null {\n const d = document as any;\n return d.fullscreenElement ?? d.webkitFullscreenElement ?? null;\n }\n\n private _fullscreenChangeEventName(): string {\n return \"onfullscreenchange\" in document ? \"fullscreenchange\" : \"webkitfullscreenchange\";\n }\n\n // --- Internal ---\n\n private _onFullscreenChange = (): void => {\n this._applyActive();\n };\n\n // Re-derive `active` by comparing document.fullscreenElement (incl. legacy\n // fallback) against *this instance's* resolved target (§2/§2.1/§5). A null\n // resolved target always yields active=false — there is nothing for this\n // instance to claim as \"mine\".\n private _applyActive(): void {\n const next = this._resolvedTarget !== null && this._fullscreenElement() === this._resolvedTarget;\n this._setActive(next);\n }\n\n private _setActive(v: boolean): void {\n if (this._active === v) return; // same-value guard (§3.3 MUST)\n this._active = v;\n this._target.dispatchEvent(new CustomEvent(\"wcs-fullscreen:change\", {\n detail: { active: v },\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 { FullscreenCore } from \"../core/FullscreenCore.js\";\n\n/**\n * `<wcs-fullscreen target=\"...\">` — declarative Fullscreen API control.\n *\n * Like `intersection`/`resize`, this Shell operates on a *referenced* element,\n * not itself (docs/fullscreen-tag-design.md §0): `target` resolves which\n * element `requestFullscreen()`/`exitFullscreen()` are invoked on, using the\n * exact same 3-mode resolution as `<wcs-intersect>`\n * (docs/fullscreen-tag-design.md §1):\n *\n * | `target` | operates on | display | use case |\n * |-----------------|-------------------------|-------------|--------------------------|\n * | omitted | first element child | `contents` | wrap a gallery image/video |\n * | `\"#hero\"` / sel | the matched element | `none` | point at a distant node |\n * | `\"self\"` | the element itself | `block` | fullscreen the wrapper |\n *\n * `requestFullscreen()` requires an active user gesture — this element cannot\n * manufacture one. Invoke the command from within a real click handler\n * (typically via the command-token protocol: this element subscribes with\n * `command.requestFullscreen: $command.<token>`, and a button emits the\n * token from its own click handler, e.g. `onclick: $command.<token>`).\n */\nexport class WcsFullscreen extends HTMLElement {\n // SSR (§10): the fullscreenchange subscription is established synchronously\n // on connect, but the Shell still exposes connectedCallbackPromise so the\n // state binder can await it uniformly across all IO nodes before\n // snapshotting.\n static hasConnectedCallbackPromise = true;\n\n static observedAttributes = [\"target\"];\n\n static wcBindable: IWcBindable = {\n ...FullscreenCore.wcBindable,\n inputs: [{ name: \"target\", attribute: \"target\" }],\n // Core の commands をそのまま継承(単一情報源)。network/intersection と同型。\n commands: FullscreenCore.wcBindable.commands,\n };\n\n private _core: FullscreenCore;\n private _connectedCallbackPromise: Promise<void> = Promise.resolve();\n private _internals: ElementInternals | null = null;\n\n constructor() {\n super();\n this._core = new FullscreenCore(this);\n this._internals = this._initInternals();\n this._wireStates({\n \"wcs-fullscreen: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 /**\n * Resolve `target` and request fullscreen on it. never-throw: an\n * unresolvable target or an unsupported/rejected API call are both\n * surfaced via `error`, never thrown (docs/fullscreen-tag-design.md §3/§6).\n */\n async requestFullscreen(): Promise<void> {\n const { element } = this._resolveTarget();\n await this._core.requestFullscreen(element);\n }\n\n async exitFullscreen(): Promise<void> {\n await this._core.exitFullscreen();\n }\n\n // --- Internal ---\n\n // Copied verbatim from <wcs-intersect> (Intersect.ts _resolveTarget/_safeQuery,\n // docs/fullscreen-tag-design.md §1): identical 3-mode resolution, only the\n // \"what to do with the resolved element\" step differs.\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 private _reresolve(): void {\n const { element, display } = this._resolveTarget();\n this.style.display = display;\n this._core.setTarget(element);\n }\n\n // --- Lifecycle ---\n\n connectedCallback(): void {\n this._reresolve();\n this._connectedCallbackPromise = this._core.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._reresolve();\n }\n}\n","import { WcsFullscreen } from \"./components/Fullscreen.js\";\nimport { config } from \"./config.js\";\n\nexport function registerComponents(): void {\n if (!customElements.get(config.tagNames.fullscreen)) {\n customElements.define(config.tagNames.fullscreen, WcsFullscreen);\n }\n}\n","import { setConfig } from \"./config.js\";\nimport { registerComponents } from \"./registerComponents.js\";\nimport { IWritableConfig } from \"./types.js\";\n\nexport function bootstrapFullscreen(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:{fullscreen:"wcs-fullscreen"}};function t(e){if(null===e||"object"!=typeof e)return e;Object.freeze(e);for(const s of Object.keys(e))t(e[s]);return e}function s(e){if(null===e||"object"!=typeof e)return e;const t={};for(const r of Object.keys(e))t[r]=s(e[r]);return t}let r=null;const n=e;function l(){return r||(r=t(s(e))),r}class c extends EventTarget{static wcBindable={protocol:"wc-bindable",version:1,properties:[{name:"active",event:"wcs-fullscreen:change",getter:e=>e.detail.active}],commands:[{name:"requestFullscreen",async:!0},{name:"exitFullscreen",async:!0}]};_target;_active=!1;_error=null;_resolvedTarget=null;_gen=0;_subscribed=!1;_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}setTarget(e){this._resolvedTarget=e,this._applyActive()}observe(){return this._subscribed||(this._subscribed=!0,document.addEventListener(this._fullscreenChangeEventName(),this._onFullscreenChange)),this._ready}dispose(){this._gen++,this._subscribed&&(this._subscribed=!1,document.removeEventListener(this._fullscreenChangeEventName(),this._onFullscreenChange))}async requestFullscreen(e){const t=++this._gen;if(this._resolvedTarget=e,!e)return void this._setError({message:"Fullscreen target could not be resolved."});const s=this._requestFullscreenFn(e);if(s)try{if(await s.call(e),t!==this._gen)return;this._setError(null),this._applyActive()}catch(e){if(t!==this._gen)return;this._setError(e)}else this._setError({message:"Fullscreen API is not supported."})}async exitFullscreen(){if(null===this._fullscreenElement())return;const e=this._exitFullscreenFn();if(!e)return;const t=++this._gen;try{if(await e(),t!==this._gen)return;this._setError(null),this._applyActive()}catch(e){if(t!==this._gen)return;this._setError(e)}}_requestFullscreenFn(e){return this._elementFullscreenFn(e,"requestFullscreen")??this._elementFullscreenFn(e,"webkitRequestFullscreen")}_elementFullscreenFn(e,t){return Object.prototype.hasOwnProperty.call(e,t)?e[t]:Element.prototype[t]}_exitFullscreenFn(){const e=document;return e.exitFullscreen?.bind(document)??e.webkitExitFullscreen?.bind(document)}_fullscreenElement(){const e=document;return e.fullscreenElement??e.webkitFullscreenElement??null}_fullscreenChangeEventName(){return"onfullscreenchange"in document?"fullscreenchange":"webkitfullscreenchange"}_onFullscreenChange=()=>{this._applyActive()};_applyActive(){const e=null!==this._resolvedTarget&&this._fullscreenElement()===this._resolvedTarget;this._setActive(e)}_setActive(e){this._active!==e&&(this._active=e,this._target.dispatchEvent(new CustomEvent("wcs-fullscreen:change",{detail:{active:e},bubbles:!0})))}_setError(e){this._error=e}}class i 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 requestFullscreen(){const{element:e}=this._resolveTarget();await this._core.requestFullscreen(e)}async exitFullscreen(){await this._core.exitFullscreen()}_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}}_reresolve(){const{element:e,display:t}=this._resolveTarget();this.style.display=t,this._core.setTarget(e)}connectedCallback(){this._reresolve(),this._connectedCallbackPromise=this._core.observe()}disconnectedCallback(){this._core.dispose()}attributeChangedCallback(e,t,s){t!==s&&this.isConnected&&this._reresolve()}}function a(t){var s;t&&((s=t).tagNames&&Object.assign(e.tagNames,s.tagNames),r=null),customElements.get(n.tagNames.fullscreen)||customElements.define(n.tagNames.fullscreen,i)}export{c as FullscreenCore,i as WcsFullscreen,a as bootstrapFullscreen,l as getConfig};
1
+ const e={tagNames:{fullscreen:"wcs-fullscreen"}};function t(e){if(null===e||"object"!=typeof e)return e;Object.freeze(e);for(const s of Object.keys(e))t(e[s]);return e}function s(e){if(null===e||"object"!=typeof e)return e;const t={};for(const r of Object.keys(e))t[r]=s(e[r]);return t}let r=null;const n=e;function l(){return r||(r=t(s(e))),r}class i extends EventTarget{static wcBindable={protocol:"wc-bindable",version:1,properties:[{name:"active",event:"wcs-fullscreen:change",getter:e=>e.detail.active}],commands:[{name:"requestFullscreen",async:!0},{name:"exitFullscreen",async:!0}]};_target;_active=!1;_error=null;_resolvedTarget=null;_gen=0;_subscribed=!1;_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}setTarget(e){this._resolvedTarget=e,this._applyActive()}observe(){return this._subscribed||(this._subscribed=!0,document.addEventListener(this._fullscreenChangeEventName(),this._onFullscreenChange)),this._ready}dispose(){this._gen++,this._subscribed&&(this._subscribed=!1,document.removeEventListener(this._fullscreenChangeEventName(),this._onFullscreenChange))}async requestFullscreen(e){const t=++this._gen;if(this._resolvedTarget=e,!e)return void this._setError({message:"Fullscreen target could not be resolved."});const s=this._requestFullscreenFn(e);if(s)try{if(await s.call(e),t!==this._gen)return;this._setError(null),this._applyActive()}catch(e){if(t!==this._gen)return;this._setError(e)}else this._setError({message:"Fullscreen API is not supported."})}async exitFullscreen(){if(null===this._fullscreenElement())return;const e=this._exitFullscreenFn();if(!e)return;const t=++this._gen;try{if(await e(),t!==this._gen)return;this._setError(null),this._applyActive()}catch(e){if(t!==this._gen)return;this._setError(e)}}_requestFullscreenFn(e){return this._elementFullscreenFn(e,"requestFullscreen")??this._elementFullscreenFn(e,"webkitRequestFullscreen")}_elementFullscreenFn(e,t){return Object.prototype.hasOwnProperty.call(e,t)?e[t]:Element.prototype[t]}_exitFullscreenFn(){const e=document;return e.exitFullscreen?.bind(document)??e.webkitExitFullscreen?.bind(document)}_fullscreenElement(){const e=document;return e.fullscreenElement??e.webkitFullscreenElement??null}_fullscreenChangeEventName(){return"onfullscreenchange"in document?"fullscreenchange":"webkitfullscreenchange"}_onFullscreenChange=()=>{this._applyActive()};_applyActive(){const e=null!==this._resolvedTarget&&this._fullscreenElement()===this._resolvedTarget;this._setActive(e)}_setActive(e){this._active!==e&&(this._active=e,this._target.dispatchEvent(new CustomEvent("wcs-fullscreen:change",{detail:{active:e},bubbles:!0})))}_setError(e){this._error=e}}class c extends HTMLElement{static hasConnectedCallbackPromise=!0;static observedAttributes=["target"];static wcBindable={...i.wcBindable,inputs:[{name:"target",attribute:"target"}],commands:i.wcBindable.commands};_core;_connectedCallbackPromise=Promise.resolve();_internals=null;constructor(){super(),this._core=new i(this),this._internals=this._initInternals(),this._wireStates({"wcs-fullscreen: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[s,r]of Object.entries(e))this.addEventListener(s,e=>{const s=this.hasAttribute("debug-states");for(const[n,l]of Object.entries(r(e.detail))){try{l?t.add(n):t.delete(n)}catch{}s&&this.toggleAttribute(`data-wcs-state-${n}`,l)}})}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 requestFullscreen(){const{element:e}=this._resolveTarget();await this._core.requestFullscreen(e)}async exitFullscreen(){await this._core.exitFullscreen()}_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}}_reresolve(){const{element:e,display:t}=this._resolveTarget();this.style.display=t,this._core.setTarget(e)}connectedCallback(){this._reresolve(),this._connectedCallbackPromise=this._core.observe()}disconnectedCallback(){this._core.dispose()}attributeChangedCallback(e,t,s){t!==s&&this.isConnected&&this._reresolve()}}function a(t){var s;t&&((s=t).tagNames&&Object.assign(e.tagNames,s.tagNames),r=null),customElements.get(n.tagNames.fullscreen)||customElements.define(n.tagNames.fullscreen,c)}export{i as FullscreenCore,c as WcsFullscreen,a as bootstrapFullscreen,l 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/FullscreenCore.ts","../src/components/Fullscreen.ts","../src/bootstrapFullscreen.ts","../src/registerComponents.ts"],"sourcesContent":["import { IConfig, IWritableConfig } from \"./types.js\";\n\ninterface IInternalConfig extends IConfig {\n tagNames: {\n fullscreen: string;\n };\n}\n\nconst _config: IInternalConfig = {\n tagNames: {\n fullscreen: \"wcs-fullscreen\",\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 Fullscreen API primitive. Unlike most wcstack IO nodes, this Core\n * does not operate on itself: it drives `requestFullscreen()` /\n * `exitFullscreen()` on a *referenced* Element that the Shell resolves via its\n * `target` attribute (docs/fullscreen-tag-design.md §0). The Core only ever\n * receives already-resolved `Element`s from its callers — it has no opinion on\n * how `target` selectors are parsed.\n *\n * `document.fullscreenElement` is a single document-wide value, so this Core\n * always compares against the *last element it resolved* (via\n * `requestFullscreen()`/`setTarget()`), never against \"is the document\n * fullscreen at all\" — that comparison is what keeps multiple concurrent\n * `<wcs-fullscreen>` instances from all reporting the same `active` value\n * (docs/fullscreen-tag-design.md §2.1, MUST).\n */\nexport class FullscreenCore extends EventTarget {\n static wcBindable: IWcBindable = {\n protocol: \"wc-bindable\",\n version: 1,\n properties: [\n { name: \"active\", event: \"wcs-fullscreen:change\", getter: (e: Event) => (e as CustomEvent).detail.active },\n ],\n commands: [\n { name: \"requestFullscreen\", async: true },\n { name: \"exitFullscreen\", async: true },\n ],\n };\n\n private _target: EventTarget;\n private _active: boolean = false;\n // Single error slot (§8): null means \"no recent failure\". Fullscreen's\n // gesture-rejection failure is a one-shot event, not a persistent state\n // machine like permission's 4-value surface — active/error are two\n // orthogonal, independently-observable axes.\n private _error: any = null;\n\n // The last Element this Core resolved via requestFullscreen()/setTarget().\n // Compared against document.fullscreenElement on every fullscreenchange so\n // each instance judges only its own target (§2.1). null means \"no target\n // resolved yet\" — active must stay false in that case.\n private _resolvedTarget: Element | null = null;\n\n // Generation guard (§6): Core-scoped (one per Core, not per-target),\n // mirroring fetch/upload. document.fullscreenElement is a single\n // document-wide slot, so at most one in-flight request/exit is meaningful\n // per Core at a time.\n private _gen = 0;\n\n // True once observe() has attached the document-level fullscreenchange\n // listener. Guards observe() so a redundant call does not double-subscribe;\n // dispose() resets it so a later observe() resumes cleanly.\n private _subscribed = false;\n\n // SSR (§10): no asynchronous probe to await — observe() completes\n // synchronously, 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 /**\n * Update the resolved target without issuing a fullscreen request (e.g. the\n * Shell re-resolves `target` on attribute change / connect). Re-evaluates\n * `active` against the current `document.fullscreenElement` so the state\n * stays correct even if the target changed while already fullscreen.\n */\n setTarget(element: Element | null): void {\n this._resolvedTarget = element;\n this._applyActive();\n }\n\n // Lifecycle (§10/§3.5). Idempotent: a second observe() while already\n // subscribed is a no-op (no double listener). Synchronous overall (no probe\n // to await), so the returned promise is only for API uniformity with other\n // IO nodes.\n observe(): Promise<void> {\n if (!this._subscribed) {\n this._subscribed = true;\n document.addEventListener(this._fullscreenChangeEventName(), this._onFullscreenChange);\n }\n return this._ready;\n }\n\n dispose(): void {\n this._gen++;\n if (this._subscribed) {\n this._subscribed = false;\n document.removeEventListener(this._fullscreenChangeEventName(), this._onFullscreenChange);\n }\n }\n\n /**\n * Request fullscreen on `element`. never-throw (§3/§6): a missing API or a\n * rejected promise (e.g. a `TypeError` from a call outside a user\n * gesture, per the WHATWG Fullscreen spec's transient-activation check) is\n * caught and surfaced via `error`, never thrown. The caller\n * (Shell) is responsible for resolving `target` and for ensuring this is\n * invoked from within an actual user gesture — this Core cannot manufacture\n * one (docs/fullscreen-tag-design.md §3).\n */\n async requestFullscreen(element: Element | null): Promise<void> {\n const gen = ++this._gen;\n this._resolvedTarget = element;\n if (!element) {\n // Distinct from \"API is not supported\" (below): the Shell's `target`\n // selector did not resolve to any element (missing/typo'd selector).\n // Conflating the two previously misled users into thinking Fullscreen\n // itself was unsupported when only their selector was wrong.\n this._setError({ message: \"Fullscreen target could not be resolved.\" });\n return;\n }\n const fn = this._requestFullscreenFn(element);\n if (!fn) {\n this._setError({ message: \"Fullscreen API is not supported.\" });\n return;\n }\n try {\n await fn.call(element);\n if (gen !== this._gen) return; // stale: dispose()/superseding call ran\n this._setError(null);\n this._applyActive();\n } catch (e: any) {\n if (gen !== this._gen) return; // stale\n this._setError(e);\n }\n }\n\n /**\n * Exit fullscreen. Silent no-op (§7) when nothing is currently fullscreen or\n * the API is unsupported — both are treated as \"already achieved the exit\n * intent\", not as errors, keeping repeated calls safe and never-throw.\n */\n async exitFullscreen(): Promise<void> {\n // no-op checks come BEFORE the generation bump: a call that does nothing\n // must not supersede an in-flight requestFullscreen() — bumping first\n // would make the pending request's settle handling stale and silently\n // swallow its error/active updates.\n if (this._fullscreenElement() === null) return; // already not fullscreen: silent no-op\n const fn = this._exitFullscreenFn();\n if (!fn) return; // unsupported: silent no-op (semantically already \"not fullscreen\")\n const gen = ++this._gen;\n try {\n await fn();\n if (gen !== this._gen) return; // stale\n this._setError(null);\n this._applyActive();\n } catch (e: any) {\n if (gen !== this._gen) return; // stale\n this._setError(e);\n }\n }\n\n // --- API resolution layer (§4): call-time, never cached. Lets tests\n // install/remove the standard/legacy APIs freely and lets an unsupported\n // environment be detected correctly on every call. ---\n\n private _requestFullscreenFn(el: Element): (() => Promise<void>) | undefined {\n return this._elementFullscreenFn(el, \"requestFullscreen\")\n ?? this._elementFullscreenFn(el, \"webkitRequestFullscreen\");\n }\n\n // Resolve a fullscreen method for `el` WITHOUT a naive `el[name]` lookup.\n // A plain lookup walks the whole prototype chain — and <wcs-fullscreen>\n // itself declares a `requestFullscreen()` *command* method, so when the\n // resolved target is the Shell element (target=\"self\", or target omitted\n // with no children), the naive lookup would find the Shell's own command\n // instead of the platform API and recurse infinitely (stack overflow).\n // Instead: check the element's own properties (how tests install stubs —\n // happy-dom has no Fullscreen API — and how a deliberate per-element\n // monkey-patch would appear), then jump straight to Element.prototype,\n // where the platform defines the real methods. Both the standard and the\n // legacy webkit name go through this same resolution for symmetry.\n private _elementFullscreenFn(el: Element, name: string): (() => Promise<void>) | undefined {\n if (Object.prototype.hasOwnProperty.call(el, name)) {\n return (el as any)[name];\n }\n return (Element.prototype as any)[name];\n }\n\n private _exitFullscreenFn(): (() => Promise<void>) | undefined {\n const d = document as any;\n return d.exitFullscreen?.bind(document) ?? d.webkitExitFullscreen?.bind(document);\n }\n\n private _fullscreenElement(): Element | null {\n const d = document as any;\n return d.fullscreenElement ?? d.webkitFullscreenElement ?? null;\n }\n\n private _fullscreenChangeEventName(): string {\n return \"onfullscreenchange\" in document ? \"fullscreenchange\" : \"webkitfullscreenchange\";\n }\n\n // --- Internal ---\n\n private _onFullscreenChange = (): void => {\n this._applyActive();\n };\n\n // Re-derive `active` by comparing document.fullscreenElement (incl. legacy\n // fallback) against *this instance's* resolved target (§2/§2.1/§5). A null\n // resolved target always yields active=false — there is nothing for this\n // instance to claim as \"mine\".\n private _applyActive(): void {\n const next = this._resolvedTarget !== null && this._fullscreenElement() === this._resolvedTarget;\n this._setActive(next);\n }\n\n private _setActive(v: boolean): void {\n if (this._active === v) return; // same-value guard (§3.3 MUST)\n this._active = v;\n this._target.dispatchEvent(new CustomEvent(\"wcs-fullscreen:change\", {\n detail: { active: v },\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 { FullscreenCore } from \"../core/FullscreenCore.js\";\n\n/**\n * `<wcs-fullscreen target=\"...\">` — declarative Fullscreen API control.\n *\n * Like `intersection`/`resize`, this Shell operates on a *referenced* element,\n * not itself (docs/fullscreen-tag-design.md §0): `target` resolves which\n * element `requestFullscreen()`/`exitFullscreen()` are invoked on, using the\n * exact same 3-mode resolution as `<wcs-intersect>`\n * (docs/fullscreen-tag-design.md §1):\n *\n * | `target` | operates on | display | use case |\n * |-----------------|-------------------------|-------------|--------------------------|\n * | omitted | first element child | `contents` | wrap a gallery image/video |\n * | `\"#hero\"` / sel | the matched element | `none` | point at a distant node |\n * | `\"self\"` | the element itself | `block` | fullscreen the wrapper |\n *\n * `requestFullscreen()` requires an active user gesture — this element cannot\n * manufacture one. Invoke the command from within a real click handler\n * (typically via the command-token protocol: this element subscribes with\n * `command.requestFullscreen: $command.<token>`, and a button emits the\n * token from its own click handler, e.g. `onclick: $command.<token>`).\n */\nexport class WcsFullscreen extends HTMLElement {\n // SSR (§10): the fullscreenchange subscription is established synchronously\n // on connect, but the Shell still exposes connectedCallbackPromise so the\n // state binder can await it uniformly across all IO nodes before\n // snapshotting.\n static hasConnectedCallbackPromise = true;\n\n static observedAttributes = [\"target\"];\n\n static wcBindable: IWcBindable = {\n ...FullscreenCore.wcBindable,\n inputs: [{ name: \"target\", attribute: \"target\" }],\n // Core の commands をそのまま継承(単一情報源)。network/intersection と同型。\n commands: FullscreenCore.wcBindable.commands,\n };\n\n private _core: FullscreenCore;\n private _connectedCallbackPromise: Promise<void> = Promise.resolve();\n\n constructor() {\n super();\n this._core = new FullscreenCore(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 /**\n * Resolve `target` and request fullscreen on it. never-throw: an\n * unresolvable target or an unsupported/rejected API call are both\n * surfaced via `error`, never thrown (docs/fullscreen-tag-design.md §3/§6).\n */\n async requestFullscreen(): Promise<void> {\n const { element } = this._resolveTarget();\n await this._core.requestFullscreen(element);\n }\n\n async exitFullscreen(): Promise<void> {\n await this._core.exitFullscreen();\n }\n\n // --- Internal ---\n\n // Copied verbatim from <wcs-intersect> (Intersect.ts _resolveTarget/_safeQuery,\n // docs/fullscreen-tag-design.md §1): identical 3-mode resolution, only the\n // \"what to do with the resolved element\" step differs.\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 private _reresolve(): void {\n const { element, display } = this._resolveTarget();\n this.style.display = display;\n this._core.setTarget(element);\n }\n\n // --- Lifecycle ---\n\n connectedCallback(): void {\n this._reresolve();\n this._connectedCallbackPromise = this._core.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._reresolve();\n }\n}\n","import { setConfig } from \"./config.js\";\nimport { registerComponents } from \"./registerComponents.js\";\nimport { IWritableConfig } from \"./types.js\";\n\nexport function bootstrapFullscreen(userConfig?: IWritableConfig): void {\n if (userConfig) {\n setConfig(userConfig);\n }\n registerComponents();\n}\n","import { WcsFullscreen } from \"./components/Fullscreen.js\";\nimport { config } from \"./config.js\";\n\nexport function registerComponents(): void {\n if (!customElements.get(config.tagNames.fullscreen)) {\n customElements.define(config.tagNames.fullscreen, WcsFullscreen);\n }\n}\n"],"names":["_config","tagNames","fullscreen","deepFreeze","obj","Object","freeze","key","keys","deepClone","clone","frozenConfig","config","getConfig","FullscreenCore","EventTarget","static","protocol","version","properties","name","event","getter","e","detail","active","commands","async","_target","_active","_error","_resolvedTarget","_gen","_subscribed","_ready","Promise","resolve","constructor","target","super","this","ready","error","setTarget","element","_applyActive","observe","document","addEventListener","_fullscreenChangeEventName","_onFullscreenChange","dispose","removeEventListener","requestFullscreen","gen","_setError","message","fn","_requestFullscreenFn","call","exitFullscreen","_fullscreenElement","_exitFullscreenFn","el","_elementFullscreenFn","prototype","hasOwnProperty","Element","d","bind","webkitExitFullscreen","fullscreenElement","webkitFullscreenElement","next","_setActive","v","dispatchEvent","CustomEvent","bubbles","WcsFullscreen","HTMLElement","wcBindable","inputs","attribute","_core","_connectedCallbackPromise","connectedCallbackPromise","getAttribute","value","setAttribute","_resolveTarget","display","scope","getRootNode","_safeQuery","child","firstElementChild","selector","querySelector","_reresolve","style","connectedCallback","disconnectedCallback","attributeChangedCallback","_name","oldValue","newValue","isConnected","bootstrapFullscreen","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/FullscreenCore.ts","../src/components/Fullscreen.ts","../src/bootstrapFullscreen.ts","../src/registerComponents.ts"],"sourcesContent":["import { IConfig, IWritableConfig } from \"./types.js\";\n\ninterface IInternalConfig extends IConfig {\n tagNames: {\n fullscreen: string;\n };\n}\n\nconst _config: IInternalConfig = {\n tagNames: {\n fullscreen: \"wcs-fullscreen\",\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 Fullscreen API primitive. Unlike most wcstack IO nodes, this Core\n * does not operate on itself: it drives `requestFullscreen()` /\n * `exitFullscreen()` on a *referenced* Element that the Shell resolves via its\n * `target` attribute (docs/fullscreen-tag-design.md §0). The Core only ever\n * receives already-resolved `Element`s from its callers — it has no opinion on\n * how `target` selectors are parsed.\n *\n * `document.fullscreenElement` is a single document-wide value, so this Core\n * always compares against the *last element it resolved* (via\n * `requestFullscreen()`/`setTarget()`), never against \"is the document\n * fullscreen at all\" — that comparison is what keeps multiple concurrent\n * `<wcs-fullscreen>` instances from all reporting the same `active` value\n * (docs/fullscreen-tag-design.md §2.1, MUST).\n */\nexport class FullscreenCore extends EventTarget {\n static wcBindable: IWcBindable = {\n protocol: \"wc-bindable\",\n version: 1,\n properties: [\n { name: \"active\", event: \"wcs-fullscreen:change\", getter: (e: Event) => (e as CustomEvent).detail.active },\n ],\n commands: [\n { name: \"requestFullscreen\", async: true },\n { name: \"exitFullscreen\", async: true },\n ],\n };\n\n private _target: EventTarget;\n private _active: boolean = false;\n // Single error slot (§8): null means \"no recent failure\". Fullscreen's\n // gesture-rejection failure is a one-shot event, not a persistent state\n // machine like permission's 4-value surface — active/error are two\n // orthogonal, independently-observable axes.\n private _error: any = null;\n\n // The last Element this Core resolved via requestFullscreen()/setTarget().\n // Compared against document.fullscreenElement on every fullscreenchange so\n // each instance judges only its own target (§2.1). null means \"no target\n // resolved yet\" — active must stay false in that case.\n private _resolvedTarget: Element | null = null;\n\n // Generation guard (§6): Core-scoped (one per Core, not per-target),\n // mirroring fetch/upload. document.fullscreenElement is a single\n // document-wide slot, so at most one in-flight request/exit is meaningful\n // per Core at a time.\n private _gen = 0;\n\n // True once observe() has attached the document-level fullscreenchange\n // listener. Guards observe() so a redundant call does not double-subscribe;\n // dispose() resets it so a later observe() resumes cleanly.\n private _subscribed = false;\n\n // SSR (§10): no asynchronous probe to await — observe() completes\n // synchronously, 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 /**\n * Update the resolved target without issuing a fullscreen request (e.g. the\n * Shell re-resolves `target` on attribute change / connect). Re-evaluates\n * `active` against the current `document.fullscreenElement` so the state\n * stays correct even if the target changed while already fullscreen.\n */\n setTarget(element: Element | null): void {\n this._resolvedTarget = element;\n this._applyActive();\n }\n\n // Lifecycle (§10/§3.5). Idempotent: a second observe() while already\n // subscribed is a no-op (no double listener). Synchronous overall (no probe\n // to await), so the returned promise is only for API uniformity with other\n // IO nodes.\n observe(): Promise<void> {\n if (!this._subscribed) {\n this._subscribed = true;\n document.addEventListener(this._fullscreenChangeEventName(), this._onFullscreenChange);\n }\n return this._ready;\n }\n\n dispose(): void {\n this._gen++;\n if (this._subscribed) {\n this._subscribed = false;\n document.removeEventListener(this._fullscreenChangeEventName(), this._onFullscreenChange);\n }\n }\n\n /**\n * Request fullscreen on `element`. never-throw (§3/§6): a missing API or a\n * rejected promise (e.g. a `TypeError` from a call outside a user\n * gesture, per the WHATWG Fullscreen spec's transient-activation check) is\n * caught and surfaced via `error`, never thrown. The caller\n * (Shell) is responsible for resolving `target` and for ensuring this is\n * invoked from within an actual user gesture — this Core cannot manufacture\n * one (docs/fullscreen-tag-design.md §3).\n */\n async requestFullscreen(element: Element | null): Promise<void> {\n const gen = ++this._gen;\n this._resolvedTarget = element;\n if (!element) {\n // Distinct from \"API is not supported\" (below): the Shell's `target`\n // selector did not resolve to any element (missing/typo'd selector).\n // Conflating the two previously misled users into thinking Fullscreen\n // itself was unsupported when only their selector was wrong.\n this._setError({ message: \"Fullscreen target could not be resolved.\" });\n return;\n }\n const fn = this._requestFullscreenFn(element);\n if (!fn) {\n this._setError({ message: \"Fullscreen API is not supported.\" });\n return;\n }\n try {\n await fn.call(element);\n if (gen !== this._gen) return; // stale: dispose()/superseding call ran\n this._setError(null);\n this._applyActive();\n } catch (e: any) {\n if (gen !== this._gen) return; // stale\n this._setError(e);\n }\n }\n\n /**\n * Exit fullscreen. Silent no-op (§7) when nothing is currently fullscreen or\n * the API is unsupported — both are treated as \"already achieved the exit\n * intent\", not as errors, keeping repeated calls safe and never-throw.\n */\n async exitFullscreen(): Promise<void> {\n // no-op checks come BEFORE the generation bump: a call that does nothing\n // must not supersede an in-flight requestFullscreen() — bumping first\n // would make the pending request's settle handling stale and silently\n // swallow its error/active updates.\n if (this._fullscreenElement() === null) return; // already not fullscreen: silent no-op\n const fn = this._exitFullscreenFn();\n if (!fn) return; // unsupported: silent no-op (semantically already \"not fullscreen\")\n const gen = ++this._gen;\n try {\n await fn();\n if (gen !== this._gen) return; // stale\n this._setError(null);\n this._applyActive();\n } catch (e: any) {\n if (gen !== this._gen) return; // stale\n this._setError(e);\n }\n }\n\n // --- API resolution layer (§4): call-time, never cached. Lets tests\n // install/remove the standard/legacy APIs freely and lets an unsupported\n // environment be detected correctly on every call. ---\n\n private _requestFullscreenFn(el: Element): (() => Promise<void>) | undefined {\n return this._elementFullscreenFn(el, \"requestFullscreen\")\n ?? this._elementFullscreenFn(el, \"webkitRequestFullscreen\");\n }\n\n // Resolve a fullscreen method for `el` WITHOUT a naive `el[name]` lookup.\n // A plain lookup walks the whole prototype chain — and <wcs-fullscreen>\n // itself declares a `requestFullscreen()` *command* method, so when the\n // resolved target is the Shell element (target=\"self\", or target omitted\n // with no children), the naive lookup would find the Shell's own command\n // instead of the platform API and recurse infinitely (stack overflow).\n // Instead: check the element's own properties (how tests install stubs —\n // happy-dom has no Fullscreen API — and how a deliberate per-element\n // monkey-patch would appear), then jump straight to Element.prototype,\n // where the platform defines the real methods. Both the standard and the\n // legacy webkit name go through this same resolution for symmetry.\n private _elementFullscreenFn(el: Element, name: string): (() => Promise<void>) | undefined {\n if (Object.prototype.hasOwnProperty.call(el, name)) {\n return (el as any)[name];\n }\n return (Element.prototype as any)[name];\n }\n\n private _exitFullscreenFn(): (() => Promise<void>) | undefined {\n const d = document as any;\n return d.exitFullscreen?.bind(document) ?? d.webkitExitFullscreen?.bind(document);\n }\n\n private _fullscreenElement(): Element | null {\n const d = document as any;\n return d.fullscreenElement ?? d.webkitFullscreenElement ?? null;\n }\n\n private _fullscreenChangeEventName(): string {\n return \"onfullscreenchange\" in document ? \"fullscreenchange\" : \"webkitfullscreenchange\";\n }\n\n // --- Internal ---\n\n private _onFullscreenChange = (): void => {\n this._applyActive();\n };\n\n // Re-derive `active` by comparing document.fullscreenElement (incl. legacy\n // fallback) against *this instance's* resolved target (§2/§2.1/§5). A null\n // resolved target always yields active=false — there is nothing for this\n // instance to claim as \"mine\".\n private _applyActive(): void {\n const next = this._resolvedTarget !== null && this._fullscreenElement() === this._resolvedTarget;\n this._setActive(next);\n }\n\n private _setActive(v: boolean): void {\n if (this._active === v) return; // same-value guard (§3.3 MUST)\n this._active = v;\n this._target.dispatchEvent(new CustomEvent(\"wcs-fullscreen:change\", {\n detail: { active: v },\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 { FullscreenCore } from \"../core/FullscreenCore.js\";\n\n/**\n * `<wcs-fullscreen target=\"...\">` — declarative Fullscreen API control.\n *\n * Like `intersection`/`resize`, this Shell operates on a *referenced* element,\n * not itself (docs/fullscreen-tag-design.md §0): `target` resolves which\n * element `requestFullscreen()`/`exitFullscreen()` are invoked on, using the\n * exact same 3-mode resolution as `<wcs-intersect>`\n * (docs/fullscreen-tag-design.md §1):\n *\n * | `target` | operates on | display | use case |\n * |-----------------|-------------------------|-------------|--------------------------|\n * | omitted | first element child | `contents` | wrap a gallery image/video |\n * | `\"#hero\"` / sel | the matched element | `none` | point at a distant node |\n * | `\"self\"` | the element itself | `block` | fullscreen the wrapper |\n *\n * `requestFullscreen()` requires an active user gesture — this element cannot\n * manufacture one. Invoke the command from within a real click handler\n * (typically via the command-token protocol: this element subscribes with\n * `command.requestFullscreen: $command.<token>`, and a button emits the\n * token from its own click handler, e.g. `onclick: $command.<token>`).\n */\nexport class WcsFullscreen extends HTMLElement {\n // SSR (§10): the fullscreenchange subscription is established synchronously\n // on connect, but the Shell still exposes connectedCallbackPromise so the\n // state binder can await it uniformly across all IO nodes before\n // snapshotting.\n static hasConnectedCallbackPromise = true;\n\n static observedAttributes = [\"target\"];\n\n static wcBindable: IWcBindable = {\n ...FullscreenCore.wcBindable,\n inputs: [{ name: \"target\", attribute: \"target\" }],\n // Core の commands をそのまま継承(単一情報源)。network/intersection と同型。\n commands: FullscreenCore.wcBindable.commands,\n };\n\n private _core: FullscreenCore;\n private _connectedCallbackPromise: Promise<void> = Promise.resolve();\n private _internals: ElementInternals | null = null;\n\n constructor() {\n super();\n this._core = new FullscreenCore(this);\n this._internals = this._initInternals();\n this._wireStates({\n \"wcs-fullscreen: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 /**\n * Resolve `target` and request fullscreen on it. never-throw: an\n * unresolvable target or an unsupported/rejected API call are both\n * surfaced via `error`, never thrown (docs/fullscreen-tag-design.md §3/§6).\n */\n async requestFullscreen(): Promise<void> {\n const { element } = this._resolveTarget();\n await this._core.requestFullscreen(element);\n }\n\n async exitFullscreen(): Promise<void> {\n await this._core.exitFullscreen();\n }\n\n // --- Internal ---\n\n // Copied verbatim from <wcs-intersect> (Intersect.ts _resolveTarget/_safeQuery,\n // docs/fullscreen-tag-design.md §1): identical 3-mode resolution, only the\n // \"what to do with the resolved element\" step differs.\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 private _reresolve(): void {\n const { element, display } = this._resolveTarget();\n this.style.display = display;\n this._core.setTarget(element);\n }\n\n // --- Lifecycle ---\n\n connectedCallback(): void {\n this._reresolve();\n this._connectedCallbackPromise = this._core.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._reresolve();\n }\n}\n","import { setConfig } from \"./config.js\";\nimport { registerComponents } from \"./registerComponents.js\";\nimport { IWritableConfig } from \"./types.js\";\n\nexport function bootstrapFullscreen(userConfig?: IWritableConfig): void {\n if (userConfig) {\n setConfig(userConfig);\n }\n registerComponents();\n}\n","import { WcsFullscreen } from \"./components/Fullscreen.js\";\nimport { config } from \"./config.js\";\n\nexport function registerComponents(): void {\n if (!customElements.get(config.tagNames.fullscreen)) {\n customElements.define(config.tagNames.fullscreen, WcsFullscreen);\n }\n}\n"],"names":["_config","tagNames","fullscreen","deepFreeze","obj","Object","freeze","key","keys","deepClone","clone","frozenConfig","config","getConfig","FullscreenCore","EventTarget","static","protocol","version","properties","name","event","getter","e","detail","active","commands","async","_target","_active","_error","_resolvedTarget","_gen","_subscribed","_ready","Promise","resolve","constructor","target","super","this","ready","error","setTarget","element","_applyActive","observe","document","addEventListener","_fullscreenChangeEventName","_onFullscreenChange","dispose","removeEventListener","requestFullscreen","gen","_setError","message","fn","_requestFullscreenFn","call","exitFullscreen","_fullscreenElement","_exitFullscreenFn","el","_elementFullscreenFn","prototype","hasOwnProperty","Element","d","bind","webkitExitFullscreen","fullscreenElement","webkitFullscreenElement","next","_setActive","v","dispatchEvent","CustomEvent","bubbles","WcsFullscreen","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","_resolveTarget","display","scope","getRootNode","_safeQuery","child","firstElementChild","selector","querySelector","_reresolve","style","connectedCallback","disconnectedCallback","attributeChangedCallback","_name","oldValue","newValue","isConnected","bootstrapFullscreen","userConfig","partialConfig","assign","customElements","get","define"],"mappings":"AAQA,MAAMA,EAA2B,CAC/BC,SAAU,CACRC,WAAY,mBAIhB,SAASC,EAAcC,GACrB,GAAY,OAARA,GAA+B,iBAARA,EAAkB,OAAOA,EACpDC,OAAOC,OAAOF,GACd,IAAK,MAAMG,KAAOF,OAAOG,KAAKJ,GAC5BD,EAAYC,EAAgCG,IAE9C,OAAOH,CACT,CAEA,SAASK,EAAaL,GACpB,GAAY,OAARA,GAA+B,iBAARA,EAAkB,OAAOA,EACpD,MAAMM,EAAiC,CAAA,EACvC,IAAK,MAAMH,KAAOF,OAAOG,KAAKJ,GAC5BM,EAAMH,GAAOE,EAAWL,EAAgCG,IAE1D,OAAOG,CACT,CAEA,IAAIC,EAA+B,KAE5B,MAAMC,EAAkBZ,WAEfa,IAId,OAHKF,IACHA,EAAeR,EAAWM,EAAUT,KAE/BW,CACT,CCxBM,MAAOG,UAAuBC,YAClCC,kBAAiC,CAC/BC,SAAU,cACVC,QAAS,EACTC,WAAY,CACV,CAAEC,KAAM,SAAUC,MAAO,wBAAyBC,OAASC,GAAcA,EAAkBC,OAAOC,SAEpGC,SAAU,CACR,CAAEN,KAAM,oBAAqBO,OAAO,GACpC,CAAEP,KAAM,iBAAkBO,OAAO,KAI7BC,QACAC,SAAmB,EAKnBC,OAAc,KAMdC,gBAAkC,KAMlCC,KAAO,EAKPC,aAAc,EAIdC,OAAwBC,QAAQC,UAExC,WAAAC,CAAYC,GACVC,QACAC,KAAKZ,QAAUU,GAAUE,IAC3B,CAEA,SAAIC,GACF,OAAOD,KAAKN,MACd,CAEA,UAAIT,GACF,OAAOe,KAAKX,OACd,CAEA,SAAIa,GACF,OAAOF,KAAKV,MACd,CAQA,SAAAa,CAAUC,GACRJ,KAAKT,gBAAkBa,EACvBJ,KAAKK,cACP,CAMA,OAAAC,GAKE,OAJKN,KAAKP,cACRO,KAAKP,aAAc,EACnBc,SAASC,iBAAiBR,KAAKS,6BAA8BT,KAAKU,sBAE7DV,KAAKN,MACd,CAEA,OAAAiB,GACEX,KAAKR,OACDQ,KAAKP,cACPO,KAAKP,aAAc,EACnBc,SAASK,oBAAoBZ,KAAKS,6BAA8BT,KAAKU,qBAEzE,CAWA,uBAAMG,CAAkBT,GACtB,MAAMU,IAAQd,KAAKR,KAEnB,GADAQ,KAAKT,gBAAkBa,GAClBA,EAMH,YADAJ,KAAKe,UAAU,CAAEC,QAAS,6CAG5B,MAAMC,EAAKjB,KAAKkB,qBAAqBd,GACrC,GAAKa,EAIL,IAEE,SADMA,EAAGE,KAAKf,GACVU,IAAQd,KAAKR,KAAM,OACvBQ,KAAKe,UAAU,MACff,KAAKK,cACP,CAAE,MAAOtB,GACP,GAAI+B,IAAQd,KAAKR,KAAM,OACvBQ,KAAKe,UAAUhC,EACjB,MAXEiB,KAAKe,UAAU,CAAEC,QAAS,oCAY9B,CAOA,oBAAMI,GAKJ,GAAkC,OAA9BpB,KAAKqB,qBAA+B,OACxC,MAAMJ,EAAKjB,KAAKsB,oBAChB,IAAKL,EAAI,OACT,MAAMH,IAAQd,KAAKR,KACnB,IAEE,SADMyB,IACFH,IAAQd,KAAKR,KAAM,OACvBQ,KAAKe,UAAU,MACff,KAAKK,cACP,CAAE,MAAOtB,GACP,GAAI+B,IAAQd,KAAKR,KAAM,OACvBQ,KAAKe,UAAUhC,EACjB,CACF,CAMQ,oBAAAmC,CAAqBK,GAC3B,OAAOvB,KAAKwB,qBAAqBD,EAAI,sBAChCvB,KAAKwB,qBAAqBD,EAAI,0BACrC,CAaQ,oBAAAC,CAAqBD,EAAa3C,GACxC,OAAIf,OAAO4D,UAAUC,eAAeP,KAAKI,EAAI3C,GACnC2C,EAAW3C,GAEb+C,QAAQF,UAAkB7C,EACpC,CAEQ,iBAAA0C,GACN,MAAMM,EAAIrB,SACV,OAAOqB,EAAER,gBAAgBS,KAAKtB,WAAaqB,EAAEE,sBAAsBD,KAAKtB,SAC1E,CAEQ,kBAAAc,GACN,MAAMO,EAAIrB,SACV,OAAOqB,EAAEG,mBAAqBH,EAAEI,yBAA2B,IAC7D,CAEQ,0BAAAvB,GACN,MAAO,uBAAwBF,SAAW,mBAAqB,wBACjE,CAIQG,oBAAsB,KAC5BV,KAAKK,gBAOC,YAAAA,GACN,MAAM4B,EAAgC,OAAzBjC,KAAKT,iBAA4BS,KAAKqB,uBAAyBrB,KAAKT,gBACjFS,KAAKkC,WAAWD,EAClB,CAEQ,UAAAC,CAAWC,GACbnC,KAAKX,UAAY8C,IACrBnC,KAAKX,QAAU8C,EACfnC,KAAKZ,QAAQgD,cAAc,IAAIC,YAAY,wBAAyB,CAClErD,OAAQ,CAAEC,OAAQkD,GAClBG,SAAS,KAEb,CAEQ,SAAAvB,CAAUb,GAChBF,KAAKV,OAASY,CAChB,ECnNI,MAAOqC,UAAsBC,YAKjChE,oCAAqC,EAErCA,0BAA4B,CAAC,UAE7BA,kBAAiC,IAC5BF,EAAemE,WAClBC,OAAQ,CAAC,CAAE9D,KAAM,SAAU+D,UAAW,WAEtCzD,SAAUZ,EAAemE,WAAWvD,UAG9B0D,MACAC,0BAA2ClD,QAAQC,UACnDkD,WAAsC,KAE9C,WAAAjD,GACEE,QACAC,KAAK4C,MAAQ,IAAItE,EAAe0B,MAChCA,KAAK8C,WAAa9C,KAAK+C,iBACvB/C,KAAKgD,YAAY,CACf,wBAA0BpB,KAAS3C,QAAsB,IAAd2C,GAAG3C,UAElD,CAMA,eAAIgE,GACF,OAAOjD,KAAK8C,WAAa,IAAI9C,KAAK8C,WAAWI,QAAU,EACzD,CAEQ,cAAAH,GAMN,IACE,GAAoC,mBAAzB/C,KAAKmD,gBAAgC,OAAO,KACvD,MAAMC,EAAYpD,KAAKmD,kBAGvB,OAFAC,EAAUF,OAAOG,IAAI,aACrBD,EAAUF,OAAOI,OAAO,aACjBF,CACT,CAAE,MACA,OAAO,IACT,CACF,CAEQ,WAAAJ,CAAYO,GAClB,GAAwB,OAApBvD,KAAK8C,WAAqB,OAC9B,MAAMI,EAASlD,KAAK8C,WAAWI,OAC/B,IAAK,MAAOrE,EAAO2E,KAAa3F,OAAO4F,QAAQF,GAC7CvD,KAAKQ,iBAAiB3B,EAAQE,IAC5B,MAAM2E,EAAQ1D,KAAK2D,aAAa,gBAChC,IAAK,MAAO/E,EAAMgF,KAAO/F,OAAO4F,QAAQD,EAAUzE,EAAkBC,SAAU,CAC5E,IACM4E,EAAMV,EAAOG,IAAIzE,GAAgBsE,EAAOI,OAAO1E,EACrD,CAAE,MAA0B,CACxB8E,GAAO1D,KAAK6D,gBAAgB,kBAAkBjF,IAAQgF,EAC5D,GAGN,CAEA,4BAAIE,GACF,OAAO9D,KAAK6C,yBACd,CAIA,UAAI/C,GACF,OAAOE,KAAK+D,aAAa,WAAa,EACxC,CAEA,UAAIjE,CAAOkE,GACThE,KAAKiE,aAAa,SAAUD,EAC9B,CAIA,UAAI/E,GACF,OAAOe,KAAK4C,MAAM3D,MACpB,CAEA,SAAIiB,GACF,OAAOF,KAAK4C,MAAM1C,KACpB,CASA,uBAAMW,GACJ,MAAMT,QAAEA,GAAYJ,KAAKkE,uBACnBlE,KAAK4C,MAAM/B,kBAAkBT,EACrC,CAEA,oBAAMgB,SACEpB,KAAK4C,MAAMxB,gBACnB,CAOQ,cAAA8C,GACN,MAAMpE,EAASE,KAAKF,OACpB,GAAe,SAAXA,EACF,MAAO,CAAEM,QAASJ,KAAMmE,QAAS,SAEnC,GAAe,KAAXrE,EAAe,CACjB,MAAMsE,EAAQpE,KAAKqE,cACnB,MAAO,CAAEjE,QAASJ,KAAKsE,WAAWF,EAAOtE,GAASqE,QAAS,OAC7D,CACA,MAAMI,EAAQvE,KAAKwE,kBACnB,OAAID,EACK,CAAEnE,QAASmE,EAAOJ,QAAS,YAE7B,CAAE/D,QAASJ,KAAMmE,QAAS,QACnC,CAEQ,UAAAG,CAAWF,EAA8BK,GAC/C,IACE,OAAOL,EAAMM,cAAcD,EAC7B,CAAE,MACA,OAAO,IACT,CACF,CAEQ,UAAAE,GACN,MAAMvE,QAAEA,EAAO+D,QAAEA,GAAYnE,KAAKkE,iBAClClE,KAAK4E,MAAMT,QAAUA,EACrBnE,KAAK4C,MAAMzC,UAAUC,EACvB,CAIA,iBAAAyE,GACE7E,KAAK2E,aACL3E,KAAK6C,0BAA4B7C,KAAK4C,MAAMtC,SAC9C,CAEA,oBAAAwE,GACE9E,KAAK4C,MAAMjC,SACb,CAEA,wBAAAoE,CAAyBC,EAAeC,EAAyBC,GAC3DD,IAAaC,GACZlF,KAAKmF,aACVnF,KAAK2E,YACP,ECpLI,SAAUS,EAAoBC,GHuC9B,IAAoBC,EGtCpBD,KHsCoBC,EGrCZD,GHsCM5H,UAChBI,OAAO0H,OAAO/H,EAAQC,SAAU6H,EAAc7H,UAEhDU,EAAe,MI3CVqH,eAAeC,IAAIrH,EAAOX,SAASC,aACtC8H,eAAeE,OAAOtH,EAAOX,SAASC,WAAY6E,EDItD"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@wcstack/fullscreen",
3
- "version": "1.16.0",
3
+ "version": "1.18.0",
4
4
  "description": "Declarative Fullscreen API component for Web Components. Framework-agnostic requestFullscreen()/exitFullscreen() control via wc-bindable-protocol.",
5
5
  "type": "module",
6
6
  "main": "./dist/index.esm.js",