vue-screenfull 1.0.9 → 1.1.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.md CHANGED
@@ -8,8 +8,8 @@
8
8
  [license-image]: https://img.shields.io/npm/l/vue-screenfull.svg
9
9
  [license-url]: https://github.com/chengchuu/vue-screenfull/blob/main/LICENSE
10
10
 
11
- Reactive, strongly typed, SSR-safe fullscreen utilities designed for Vue 3.
12
- An optional CSS pseudo-fullscreen fallback is also available.
11
+ Reactive, strongly typed, and SSR-safe fullscreen utilities for Vue 3, with an optional CSS
12
+ pseudo-fullscreen fallback.
13
13
 
14
14
  - [Project website](https://chengchuu.github.io/vue-screenfull/)
15
15
  - [Live playground](https://chengchuu.github.io/vue-screenfull/playground/)
@@ -21,9 +21,7 @@ An optional CSS pseudo-fullscreen fallback is also available.
21
21
  - Standard, WebKit, Mozilla, and Microsoft-prefixed API detection.
22
22
  - Vue template refs, component refs, elements, and safe CSS selectors.
23
23
  - Structured results and actionable errors instead of swallowed rejections.
24
- - Renderless component, directive, optional plugin, and framework-light controller.
25
- - No fullscreen wrapper or other runtime dependency; Vue remains a peer dependency.
26
- - CJS, ESM, browser IIFE, source maps, and declarations.
24
+ - Renderless component, directive, optional plugin, and framework-neutral controller.
27
25
 
28
26
  ## Installation
29
27
 
@@ -31,17 +29,8 @@ An optional CSS pseudo-fullscreen fallback is also available.
31
29
  npm install vue-screenfull
32
30
  ```
33
31
 
34
- The browser bundle is `lib/vue-screenfull.min.js`, exposes `VUE_SCREENFULL`, and expects Vue to be available as the global `Vue`.
35
-
36
- ## Browser Support
37
-
38
- Support is feature-detected at runtime. Current Chrome, Edge, Firefox, and Safari desktop releases,
39
- Chrome/Firefox/Samsung Internet on Android, and Safari on iPadOS commonly expose the API. iPhone
40
- Safari, Android/iOS WebViews, managed devices, and embedded documents may restrict arbitrary-element
41
- fullscreen. This policy describes targets, not a guarantee for every OS/browser release.
42
-
43
- Native fullscreen can hide more browser UI, but the browser and operating system retain control.
44
- The CSS fallback only fills the visual viewport and never claims to hide system or browser chrome.
32
+ `lib/vue-screenfull.min.js` exposes `VUE_SCREENFULL` and requires the global `Vue`. Although Vue is
33
+ an optional peer dependency, package-root imports still require Vue 3 at runtime.
45
34
 
46
35
  ## Basic Usage
47
36
 
@@ -65,8 +54,8 @@ const { isEnabled, isFullscreen, error, toggle } = useScreenfull();
65
54
  </template>
66
55
  ```
67
56
 
68
- Call `request` or `toggle` directly inside a click, keyboard, or touch handler.
69
- Browsers normally require transient user activation and can reject even when `isEnabled.value` is true.
57
+ Call `request` or `toggle` directly from a click, keyboard, or touch handler. Browsers normally
58
+ require transient user activation and can reject a request even when `isEnabled.value` is true.
70
59
 
71
60
  ## Fullscreen a Specific Element
72
61
 
@@ -86,7 +75,8 @@ const { request, isFullscreen } = useScreenfullTarget(panel);
86
75
  ```
87
76
 
88
77
  `useScreenfull().request()` with no target opens `document.documentElement`.
89
- A selector such as `request("#player")` is resolved with `document.querySelector`; invalid or unmatched selectors return `INVALID_TARGET`.
78
+ A selector such as `request("#player")` is resolved with `document.querySelector`. Invalid or
79
+ unmatched selectors return `INVALID_TARGET`.
90
80
 
91
81
  ## Toggle Fullscreen
92
82
 
@@ -104,8 +94,9 @@ Some mobile browsers offer video-only fullscreen independently of arbitrary-elem
104
94
  <button type="button" @click="exit">Exit fullscreen</button>
105
95
  ```
106
96
 
107
- Always include a visible exit button, particularly when fallback is enabled. Escape often exits,
108
- but browser Escape behavior cannot be overridden reliably. Exits initiated by browser UI are reflected through native change events.
97
+ Always include a visible exit button, particularly when fallback is enabled. Escape often exits
98
+ fullscreen, but its browser behavior cannot be overridden reliably. Native change events reflect
99
+ exits initiated through the browser UI.
109
100
 
110
101
  ## Check Support
111
102
 
@@ -145,18 +136,20 @@ const { request, exit, isFallback } = useScreenfull({
145
136
  });
146
137
  ```
147
138
 
148
- CSS fallback fixes an `HTMLElement` to the visual viewport, preserves every inline style it changes,
149
- locks and restores background body scrolling for element targets, keeps whole-page targets scrollable,
150
- preserves the scroll position, adds the configured class, exits on Escape when possible, and restores
151
- focus. Cleanup also runs when its Vue scope is disposed.
152
- It is pseudo-fullscreen: it cannot hide address bars, browser controls, notifications,
153
- or operating-system UI. Keep an accessible exit button inside the target:
139
+ CSS fallback fixes an `HTMLElement` to the visual viewport and preserves every inline style that it
140
+ changes. For element targets, it locks and restores background body scrolling. It keeps whole-page
141
+ targets scrollable, preserves the scroll position, adds the configured class, exits on Escape when
142
+ possible, and restores focus. Cleanup also runs when its Vue scope is disposed.
143
+
144
+ This mode is pseudo-fullscreen. It cannot hide address bars, browser controls, notifications, or
145
+ operating-system UI. Keep an accessible exit button inside the target:
154
146
 
155
147
  ```vue
156
148
  <button type="button" @click="exit">Close full-page view</button>
157
149
  ```
158
150
 
159
- A custom fallback implements `enter(context)` and `exit(context)` and is responsible for complete cleanup.
151
+ A custom fallback implements `enter(context)` and `exit(context)` and is responsible for complete
152
+ cleanup.
160
153
 
161
154
  ## Component Usage
162
155
 
@@ -174,8 +167,8 @@ A custom fallback implements `enter(context)` and `exit(context)` and is respons
174
167
  </Screenfull>
175
168
  ```
176
169
 
177
- The renderless component emits `change`, `enter`, `exit`, `error`, and `fallback`.
178
- Its default slot receives all composable refs and actions; it imposes no visual system.
170
+ The renderless component emits `change`, `enter`, `exit`, `error`, and `fallback`. Its default slot
171
+ receives all composable refs and actions without imposing a visual system.
179
172
 
180
173
  ## Directive Usage
181
174
 
@@ -206,15 +199,96 @@ import App from "./App.vue";
206
199
  createApp(App).use(VueScreenfull).mount("#app");
207
200
  ```
208
201
 
209
- This registers `Screenfull` and `v-screenfull`. Names can be changed with `componentName` and `directiveName`.
210
- Named composable imports never require plugin installation and remain tree-shakable.
202
+ This registers `Screenfull` and `v-screenfull`. Use `componentName` and `directiveName` to change
203
+ their names. Named composable imports do not require plugin installation and remain tree-shakable.
204
+
205
+ ## Vue-free Browser Entry
206
+
207
+ Use `vue-screenfull/browser` when the caller does not own a Vue root. This subpath exports only
208
+ `createScreenfullController`, `detectFullscreenApi`, and their framework-neutral types. It does not
209
+ load Vue or Mazey at runtime.
210
+
211
+ With npm:
212
+
213
+ ```ts
214
+ import {
215
+ createScreenfullController,
216
+ type ScreenfullChangeListener,
217
+ } from "vue-screenfull/browser";
218
+
219
+ const controller = createScreenfullController({ restoreFocus: true });
220
+ const target = document.querySelector("#player");
221
+ const button = document.querySelector("#toggle-fullscreen");
222
+ const toggle = () => controller.toggle(target);
223
+ const onChange: ScreenfullChangeListener = (state) => {
224
+ console.log(state.isFullscreen, state.element);
225
+ };
226
+
227
+ button?.addEventListener("click", toggle);
228
+ controller.on("change", onChange);
229
+
230
+ async function dispose() {
231
+ button?.removeEventListener("click", toggle);
232
+ controller.off("change", onChange);
233
+ await controller.destroy();
234
+ }
235
+
236
+ // Call dispose() when the integration is disposed.
237
+ ```
238
+
239
+ As a native browser ES module:
240
+
241
+ ```html
242
+ <script type="module">
243
+ import { createScreenfullController } from "https://cdn.jsdelivr.net/npm/vue-screenfull/lib/browser.mjs";
244
+
245
+ const controller = createScreenfullController();
246
+ const target = document.querySelector("#player");
247
+ const button = document.querySelector("#toggle-fullscreen");
248
+ const toggle = () => controller.toggle(target);
249
+
250
+ button?.addEventListener("click", toggle);
251
+
252
+ async function dispose() {
253
+ button?.removeEventListener("click", toggle);
254
+ await controller.destroy();
255
+ }
256
+
257
+ // Call dispose() when the integration is disposed.
258
+ </script>
259
+ ```
260
+
261
+ As a classic script:
262
+
263
+ ```html
264
+ <script src="https://cdn.jsdelivr.net/npm/vue-screenfull/lib/vue-screenfull.browser.min.js"></script>
265
+ <script>
266
+ const controller = VUE_SCREENFULL_BROWSER.createScreenfullController();
267
+ const target = document.querySelector("#player");
268
+ const button = document.querySelector("#toggle-fullscreen");
269
+ const toggle = () => controller.toggle(target);
270
+
271
+ button?.addEventListener("click", toggle);
272
+
273
+ function dispose() {
274
+ button?.removeEventListener("click", toggle);
275
+ return controller.destroy();
276
+ }
277
+
278
+ // Call dispose() when the integration is disposed.
279
+ </script>
280
+ ```
281
+
282
+ Call `request` or `toggle` directly from a click, keyboard, or touch handler because browsers
283
+ normally require transient user activation. Retain the controller and call `destroy()` when the
284
+ integration is disposed so its listeners and any active CSS fallback are cleaned up.
211
285
 
212
286
  ## Advanced Usage
213
287
 
214
- The framework-light controller is useful for migration and non-component integrations:
288
+ The framework-neutral controller is useful for migration and non-component integrations:
215
289
 
216
290
  ```ts
217
- import { createScreenfullController } from "vue-screenfull";
291
+ import { createScreenfullController } from "vue-screenfull/browser";
218
292
 
219
293
  const controller = createScreenfullController({ restoreFocus: true });
220
294
  const onChange = (state) => console.log(state.isFullscreen, state.element);
@@ -224,10 +298,10 @@ controller.off("change", onChange);
224
298
  await controller.destroy();
225
299
  ```
226
300
 
227
- `raw` is a read-only diagnostic mapping of detected browser property/event names, or `null`.
228
- It is not the recommended API. Each composable creates one controller and disposes it with its Vue scope;
229
- multiple controllers synchronize through the same document's native events.
230
- Importing the package does not register listeners or touch the DOM.
301
+ `raw` is a read-only diagnostic mapping of detected browser property and event names, or `null`. It
302
+ is not the recommended API. Each composable creates one controller and disposes it with its Vue
303
+ scope. Multiple controllers synchronize through the same document's native events. Importing the
304
+ package does not register listeners or touch the DOM.
231
305
 
232
306
  Reactive callbacks can observe changes without duplicate component wiring:
233
307
 
@@ -236,7 +310,8 @@ useScreenfull({ onEnter: announce, onExit: announce, onError: report });
236
310
  ```
237
311
 
238
312
  `restoreFocus: true` (the default) focuses the initiating element after exit where practical.
239
- `exitOnRouteChange` listens for browser `popstate`; router-specific navigation can instead call `exit()` in the application's own route hook.
313
+ `exitOnRouteChange` listens for browser `popstate`. For router-specific navigation, call `exit()`
314
+ from the application's route hook instead.
240
315
 
241
316
  ## iframe Usage
242
317
 
@@ -250,9 +325,9 @@ The embedding page controls permission. A typical iframe is:
250
325
  ></iframe>
251
326
  ```
252
327
 
253
- Permissions Policy or a missing iframe permission can still reject.
254
- The library returns `IFRAME_PERMISSION_REQUIRED` when a denial can be associated with an embedded document;
255
- it cannot override the parent page's policy.
328
+ A Permissions Policy restriction or missing iframe permission can still reject the request. The
329
+ library returns `IFRAME_PERMISSION_REQUIRED` when it can associate a denial with an embedded
330
+ document. It cannot override the parent page's policy.
256
331
 
257
332
  ## Mobile Considerations
258
333
 
@@ -263,10 +338,21 @@ it cannot override the parent page's policy.
263
338
  - Native navigation, tab switching, app switching, and OS gestures may exit fullscreen.
264
339
  - Neither native capability nor this library guarantees browser/OS controls disappear.
265
340
 
341
+ ## Browser Support
342
+
343
+ Support is detected at runtime. Current desktop releases of Chrome, Edge, Firefox, and Safari
344
+ commonly expose the API. Chrome, Firefox, and Samsung Internet on Android and Safari on iPadOS also
345
+ commonly expose it. iPhone Safari, Android and iOS WebViews, managed devices, and embedded documents
346
+ may restrict arbitrary-element fullscreen. This policy identifies support targets; it does not
347
+ guarantee support in every browser or operating-system release.
348
+
349
+ Native fullscreen can hide more browser UI, but the browser and operating system retain control.
350
+ The CSS fallback only fills the visual viewport and never claims to hide system or browser chrome.
351
+
266
352
  ## SSR and Nuxt
267
353
 
268
354
  Imports are safe in Vite SSR, Nuxt 3, Node tests, and static generation. Outside a browser,
269
- `isEnabled` is false, status is `unsupported`, and actions return `NOT_IN_BROWSER`.
355
+ `isEnabled` is `false`, the status is `unsupported`, and actions return `NOT_IN_BROWSER`.
270
356
 
271
357
  ```vue
272
358
  <script setup lang="ts">
@@ -286,16 +372,16 @@ const screenfull = useScreenfull(); // safe during Nuxt setup/SSR
286
372
  </template>
287
373
  ```
288
374
 
289
- When destructuring refs in `<script setup>`, templates unwrap them automatically;
290
- when accessing through an object as above, use `.value` in script expressions.
375
+ Templates automatically unwrap refs destructured in `<script setup>`. When accessing refs through
376
+ an object as shown in the example, use `.value` in script expressions.
291
377
 
292
378
  ## Migrating from screenfull
293
379
 
294
- `vue-screenfull` is an independent Vue 3 library inspired by screenfull's public API and compatibility goals.
295
- It is not drop-in compatible and is not endorsed by screenfull's maintainers.
380
+ `vue-screenfull` is an independent Vue 3 library inspired by screenfull's public API and
381
+ compatibility goals. It is not drop-in compatible and is not endorsed by screenfull's maintainers.
296
382
 
297
383
  | screenfull concept | vue-screenfull equivalent |
298
- | -------------------------------------- | ------------------------------------------------------- |
384
+ | :------------------------------------- | :------------------------------------------------------ |
299
385
  | `screenfull.request(element, options)` | `request(element, options)` |
300
386
  | `screenfull.exit()` | `exit()` |
301
387
  | `screenfull.toggle(element, options)` | `toggle(element, options)` |
@@ -323,9 +409,10 @@ if (isEnabled.value) {
323
409
  }
324
410
  ```
325
411
 
326
- Key differences are reactive refs, automatic lifecycle cleanup, SSR-safe imports, structured results/errors, optional pseudo-fullscreen, and Vue component/directive APIs.
327
- Controller listeners receive typed state/errors rather than raw DOM events.
328
- Legacy `onchange`/`onerror` aliases are not provided. The plugin is optional.
412
+ Key differences include reactive refs, automatic lifecycle cleanup, SSR-safe imports, structured
413
+ results and errors, optional pseudo-fullscreen, and Vue component and directive APIs. Controller
414
+ listeners receive typed state and errors instead of raw DOM events. Legacy `onchange` and `onerror`
415
+ aliases are not provided. The plugin is optional.
329
416
 
330
417
  ## API Reference
331
418
 
@@ -337,39 +424,46 @@ Root exports:
337
424
  - `detectFullscreenApi(document)` and `resolveScreenfullTarget(target, document)`
338
425
  - all public target, option, state, result, error, event, component, directive, plugin, and raw-map types
339
426
 
340
- Actions resolve to `{ ok, mode, element, error }`; `mode` is `native`, `fallback`, or `none`.
341
- Generated TypeDoc is published at [chengchuu.github.io/vue-screenfull/api/](https://chengchuu.github.io/vue-screenfull/api/).
427
+ The `vue-screenfull/browser` subpath exports `createScreenfullController`, `detectFullscreenApi`,
428
+ and only framework-neutral controller types.
429
+
430
+ Actions resolve to `{ ok, mode, element, error }`. The `mode` value is `native`, `fallback`, or
431
+ `none`. Generated TypeDoc is published at
432
+ [chengchuu.github.io/vue-screenfull/api/](https://chengchuu.github.io/vue-screenfull/api/).
342
433
 
343
434
  ## Live Playground
344
435
 
345
- The deployed playground is at [chengchuu.github.io/vue-screenfull/playground/](https://chengchuu.github.io/vue-screenfull/playground/).
346
- It includes page, element, image-style, and video targets; explicit exit; diagnostics;
347
- invalid-target feedback; event history; accessibility, iframe, mobile, and migration notes. Run it locally with:
436
+ The deployed playground is available at
437
+ [chengchuu.github.io/vue-screenfull/playground/](https://chengchuu.github.io/vue-screenfull/playground/).
438
+ It includes page, element, image-style, and video targets; explicit exit controls; diagnostics;
439
+ invalid-target feedback; event history; and accessibility, iframe, mobile, and migration notes. Run
440
+ it locally with:
348
441
 
349
442
  ```bash
350
443
  npm run dev
351
444
  ```
352
445
 
353
- Native fullscreen automation is intentionally not treated as universally reliable because browsers enforce user activation.
446
+ Native fullscreen automation is intentionally not treated as universally reliable because browsers
447
+ enforce user activation.
354
448
 
355
449
  ## Installable Documentation Website
356
450
 
357
- The project website is a Progressive Web App scoped to `/vue-screenfull/`. Its homepage,
358
- playground, and API documentation share a generated manifest and a Google Workbox v7 service
359
- worker. Documents, scripts, and styles use bounded network-first caches so current documentation
360
- normally wins without pairing fresh HTML with stale bundles; local images and fonts use bounded
361
- cache-first storage. A precached offline page is used only when a requested document is unavailable
362
- from both the network and runtime cache.
451
+ The project website is a Progressive Web App scoped to `/vue-screenfull/`. Its homepage, playground,
452
+ and API documentation share a generated manifest and a Google Workbox v7 service worker. Documents,
453
+ scripts, and styles use bounded network-first caches. This strategy normally prioritizes current
454
+ documentation without pairing fresh HTML with stale bundles. Local images and fonts use bounded
455
+ cache-first storage. The site uses a precached offline page only when the requested document is
456
+ unavailable from both the network and the runtime cache.
363
457
 
364
- Installation uses the browser's native `beforeinstallprompt` flow when available. The site never
365
- opens that prompt automatically, and browsers without a custom prompt can use their menu or, on
366
- iOS/iPadOS Safari, **Share → Add to Home Screen**. Installing this website is separate from the
458
+ Installation uses the browser's native `beforeinstallprompt` flow when available. The site does not
459
+ open that prompt automatically. In browsers without a custom prompt, use the browser menu or, on
460
+ iOS and iPadOS Safari, **Share → Add to Home Screen**. Installing the website is separate from the
367
461
  Fullscreen API and does not grant fullscreen capability.
368
462
 
369
463
  Worker updates remain user-controlled. When a new version is waiting, choose **Update now** to
370
- activate it and reload the current page once. On the playground, this explicit action is the only
371
- update path that reloads an active session. The generated worker includes a final-artifact version
372
- marker, so deployable website changes can be detected without precaching unversioned bundles.
464
+ activate it and reload the current page once. On the playground, only this explicit action reloads
465
+ an active session during an update. The generated worker includes a final-artifact version marker,
466
+ so deployable website changes can be detected without precaching unversioned bundles.
373
467
 
374
468
  ## Development
375
469
 
@@ -392,9 +486,15 @@ npm pack --dry-run
392
486
  Normal `npm run dev` does not register the production worker. Build `npm run docs` and serve the
393
487
  generated `docs` directory from localhost under `/vue-screenfull/` for production-like PWA testing.
394
488
 
395
- See [`guides/MANUAL_TESTING.md`](./guides/MANUAL_TESTING.md) for the browser matrix and real-browser strategy.
396
- Production output remains `lib/index.cjs.js`, `lib/index.esm.js`, `lib/vue-screenfull.min.js`, `lib/index.d.ts`, `lib/typing.d.ts`, and `lib/global.d.ts`. Native Node ESM resolves through the additional conditional entry `lib/index.mjs`.
489
+ See [`guides/MANUAL_TESTING.md`](./guides/MANUAL_TESTING.md) for the browser matrix and real-browser
490
+ strategy. The root entry produces `lib/index.cjs.js`, `lib/index.esm.js`, `lib/index.mjs`,
491
+ `lib/vue-screenfull.min.js`, `lib/index.d.ts`, `lib/typing.d.ts`, and `lib/global.d.ts`. The
492
+ framework-neutral entry produces `lib/browser.cjs.js`, `lib/browser.esm.js`, `lib/browser.mjs`,
493
+ `lib/browser.d.ts`, and `lib/vue-screenfull.browser.min.js`. JavaScript bundles include source maps.
397
494
 
398
495
  ## License and Attribution
399
496
 
400
- Released under the MIT License. This independent project acknowledges [screenfull](https://github.com/sindresorhus/screenfull) (MIT) for its public API and cross-browser compatibility inspiration, and `vue-fullscreen` (MIT) as a Vue ecosystem reference. No endorsement is implied.
497
+ Released under the MIT License. This independent project acknowledges
498
+ [screenfull](https://github.com/sindresorhus/screenfull) (MIT) for its public API and cross-browser
499
+ compatibility inspiration, and `vue-fullscreen` (MIT) as a Vue ecosystem reference. No endorsement
500
+ is implied.
package/README.zh-CN.md CHANGED
@@ -22,8 +22,8 @@
22
22
  - 检测带 WebKit、Mozilla、Microsoft 前缀的 API。
23
23
  - 支持 Vue 模板引用、组件引用、元素和安全的 CSS 选择器。
24
24
  - 返回结构化结果和可操作的错误,不会静默忽略 Promise 拒绝。
25
- - 提供无渲染组件、指令、可选插件和轻量级框架控制器。
26
- - 不依赖全屏包装器或其他运行时依赖;Vue 仍是对等依赖。
25
+ - 提供无渲染组件、指令、可选插件和框架无关的控制器。
26
+ - 提供适用于 npm、浏览器原生模块和经典脚本的无 Vue 浏览器入口。
27
27
  - 提供 CJS、ESM、浏览器 IIFE、源映射和类型声明。
28
28
 
29
29
  ## 安装
@@ -32,7 +32,76 @@
32
32
  npm install vue-screenfull
33
33
  ```
34
34
 
35
- 浏览器包为 `lib/vue-screenfull.min.js`。它会暴露 `VUE_SCREENFULL`,并要求通过全局变量 `Vue` 访问 Vue。
35
+ 浏览器包为 `lib/vue-screenfull.min.js`。它会暴露 `VUE_SCREENFULL`,并要求通过全局变量 `Vue` 访问 Vue。Vue 只在软件包安装层面标记为可选。通过软件包根入口导入 API 时,运行时仍需要 Vue 3。
36
+
37
+ ### 无 Vue 浏览器入口
38
+
39
+ 如果调用方没有 Vue 根实例,请使用 `vue-screenfull/browser`。该子路径只导出 `createScreenfullController`、`detectFullscreenApi` 和框架无关的类型。运行时不会加载 Vue 或 Mazey。
40
+
41
+ 通过 npm 使用:
42
+
43
+ ```ts
44
+ import { createScreenfullController } from "vue-screenfull/browser";
45
+
46
+ const controller = createScreenfullController({ restoreFocus: true });
47
+ const target = document.querySelector("#player");
48
+ const button = document.querySelector("#toggle-fullscreen");
49
+ const toggle = () => controller.toggle(target);
50
+
51
+ button?.addEventListener("click", toggle);
52
+
53
+ async function dispose() {
54
+ button?.removeEventListener("click", toggle);
55
+ await controller.destroy();
56
+ }
57
+
58
+ // 集成销毁时调用 dispose()。
59
+ ```
60
+
61
+ 通过浏览器原生 ES 模块使用:
62
+
63
+ ```html
64
+ <script type="module">
65
+ import { createScreenfullController } from "https://cdn.jsdelivr.net/npm/vue-screenfull/lib/browser.mjs";
66
+
67
+ const controller = createScreenfullController();
68
+ const target = document.querySelector("#player");
69
+ const button = document.querySelector("#toggle-fullscreen");
70
+ const toggle = () => controller.toggle(target);
71
+
72
+ button?.addEventListener("click", toggle);
73
+
74
+ async function dispose() {
75
+ button?.removeEventListener("click", toggle);
76
+ await controller.destroy();
77
+ }
78
+
79
+ // 集成销毁时调用 dispose()。
80
+ </script>
81
+ ```
82
+
83
+ 通过经典脚本使用:
84
+
85
+ ```html
86
+ <script src="https://cdn.jsdelivr.net/npm/vue-screenfull/lib/vue-screenfull.browser.min.js"></script>
87
+ <script>
88
+ const controller = VUE_SCREENFULL_BROWSER.createScreenfullController();
89
+ const target = document.querySelector("#player");
90
+ const button = document.querySelector("#toggle-fullscreen");
91
+ const toggle = () => controller.toggle(target);
92
+
93
+ button?.addEventListener("click", toggle);
94
+
95
+ function dispose() {
96
+ button?.removeEventListener("click", toggle);
97
+ return controller.destroy();
98
+ }
99
+
100
+ // 集成销毁时调用 dispose()。
101
+ </script>
102
+ ```
103
+
104
+ 请在点击、键盘或触摸事件处理程序中直接调用 `request` 或 `toggle`。浏览器通常要求短暂的用户激活状态。请保留控制器,并在集成销毁时调用 `destroy()`。该方法会清理监听器和正在运行的 CSS 回退方案。
36
105
 
37
106
  ## 浏览器支持
38
107
 
@@ -196,10 +265,10 @@ createApp(App).use(VueScreenfull).mount("#app");
196
265
 
197
266
  ## 高级用法
198
267
 
199
- 轻量级框架控制器适用于迁移和非组件集成:
268
+ 框架无关的控制器适用于迁移和非组件集成:
200
269
 
201
270
  ```ts
202
- import { createScreenfullController } from "vue-screenfull";
271
+ import { createScreenfullController } from "vue-screenfull/browser";
203
272
 
204
273
  const controller = createScreenfullController({ restoreFocus: true });
205
274
  const onChange = (state) => console.log(state.isFullscreen, state.element);
@@ -313,6 +382,8 @@ if (isEnabled.value) {
313
382
 
314
383
  操作会解析为 `{ ok, mode, element, error }`。`mode` 为 `native`、`fallback` 或 `none`。生成的 TypeDoc 发布于 [API 文档网站](https://chengchuu.github.io/vue-screenfull/api/)。
315
384
 
385
+ `vue-screenfull/browser` 子路径只导出 `createScreenfullController`、`detectFullscreenApi` 和框架无关的控制器类型。
386
+
316
387
  ## 在线演练场
317
388
 
318
389
  已部署的版本位于 [vue-screenfull 在线演练场](https://chengchuu.github.io/vue-screenfull/playground/)。其中包含页面、元素、图片样式和视频目标。它还提供显式退出、诊断、无效目标反馈和事件历史记录。其他内容包括无障碍、iframe、移动端和迁移说明。使用以下命令在本地运行:
@@ -351,16 +422,25 @@ npm pack --dry-run
351
422
 
352
423
  常规的 `npm run dev` 不会注册生产环境 Worker。若要在类似生产环境中测试 PWA,请运行 `npm run docs`。然后在 localhost 的 `/vue-screenfull/` 路径下提供生成的 `docs` 目录。
353
424
 
354
- 有关浏览器矩阵和真实浏览器测试策略,请参阅 [`guides/MANUAL_TESTING.md`](./guides/MANUAL_TESTING.md)。生产输出仍包含以下文件:
425
+ 有关浏览器矩阵和真实浏览器测试策略,请参阅 [`guides/MANUAL_TESTING.md`](./guides/MANUAL_TESTING.md)。根入口会生成以下文件:
355
426
 
356
427
  - `lib/index.cjs.js`
357
428
  - `lib/index.esm.js`
429
+ - `lib/index.mjs`
358
430
  - `lib/vue-screenfull.min.js`
359
431
  - `lib/index.d.ts`
360
432
  - `lib/typing.d.ts`
361
433
  - `lib/global.d.ts`
362
434
 
363
- 原生 Node ESM 通过额外的条件入口 `lib/index.mjs` 解析。
435
+ 框架无关的入口会生成以下文件:
436
+
437
+ - `lib/browser.cjs.js`
438
+ - `lib/browser.esm.js`
439
+ - `lib/browser.mjs`
440
+ - `lib/browser.d.ts`
441
+ - `lib/vue-screenfull.browser.min.js`
442
+
443
+ JavaScript 软件包会包含源映射。
364
444
 
365
445
  ## 许可证与致谢
366
446
 
@@ -0,0 +1,7 @@
1
+ /*!
2
+ * vue-screenfull v1.1.0
3
+ * (c) 2018-2026 Cheng https://www.npmjs.com/package/vue-screenfull
4
+ * Released under the MIT License.
5
+ */
6
+ "use strict";function e(e,n){(null==n||n>e.length)&&(n=e.length);for(var r=0,t=Array(n);r<n;r++)t[r]=e[r];return t}function n(e,n,r){return n&&function(e,n){for(var r=0;r<n.length;r++){var t=n[r];t.enumerable=t.enumerable||!1,t.configurable=!0,"value"in t&&(t.writable=!0),Object.defineProperty(e,o(t.key),t)}}(e.prototype,n),Object.defineProperty(e,"prototype",{writable:!1}),e}function r(){var e,n,l="function"==typeof Symbol?Symbol:{},o=l.iterator||"@@iterator",i=l.toStringTag||"@@toStringTag";function u(r,l,o,i){var u=l&&l.prototype instanceof c?l:c,s=Object.create(u.prototype);return t(s,"_invoke",function(r,t,l){var o,i,u,c=0,s=l||[],f=!1,d={p:0,n:0,v:e,a:v,f:v.bind(e,4),d:function(n,r){return o=n,i=0,u=e,d.n=r,a}};function v(r,t){for(i=r,u=t,n=0;!f&&c&&!l&&n<s.length;n++){var l,o=s[n],v=d.p,h=o[2];r>3?(l=h===t)&&(u=o[(i=o[4])?5:(i=3,3)],o[4]=o[5]=e):o[0]<=v&&((l=r<2&&v<o[1])?(i=0,d.v=t,d.n=o[1]):v<h&&(l=r<3||o[0]>t||t>h)&&(o[4]=r,o[5]=t,d.n=h,i=0))}if(l||r>1)return a;throw f=!0,t}return function(l,s,h){if(c>1)throw TypeError("Generator is already running");for(f&&1===s&&v(s,h),i=s,u=h;(n=i<2?e:u)||!f;){o||(i?i<3?(i>1&&(d.n=-1),v(i,u)):d.n=u:d.v=u);try{if(c=2,o){if(i||(l="next"),n=o[l]){if(!(n=n.call(o,u)))throw TypeError("iterator result is not an object");if(!n.done)return n;u=n.value,i<2&&(i=0)}else 1===i&&(n=o.return)&&n.call(o),i<2&&(u=TypeError("The iterator does not provide a '"+l+"' method"),i=1);o=e}else if((n=(f=d.n<0)?u:r.call(t,d))!==a)break}catch(n){o=e,i=1,u=n}finally{c=1}}return{value:n,done:f}}}(r,o,i),!0),s}var a={};function c(){}function s(){}function f(){}n=Object.getPrototypeOf;var d=[][o]?n(n([][o]())):(t(n={},o,function(){return this}),n),v=f.prototype=c.prototype=Object.create(d);function h(e){return Object.setPrototypeOf?Object.setPrototypeOf(e,f):(e.__proto__=f,t(e,i,"GeneratorFunction")),e.prototype=Object.create(v),e}return s.prototype=f,t(v,"constructor",f),t(f,"constructor",s),s.displayName="GeneratorFunction",t(f,i,"GeneratorFunction"),t(v),t(v,i,"Generator"),t(v,o,function(){return this}),t(v,"toString",function(){return"[object Generator]"}),(r=function(){return{w:u,m:h}})()}function t(e,n,r,l){var o=Object.defineProperty;try{o({},"",{})}catch(e){o=0}t=function(e,n,r,l){function i(n,r){t(e,n,function(e){return this._invoke(n,r,e)})}n?o?o(e,n,{value:r,enumerable:!l,configurable:!l,writable:!l}):e[n]=r:(i("next",0),i("throw",1),i("return",2))},t(e,n,r,l)}function l(n,r){return function(e){if(Array.isArray(e))return e}(n)||function(e,n){var r=null==e?null:"undefined"!=typeof Symbol&&e[Symbol.iterator]||e["@@iterator"];if(null!=r){var t,l,o,i,u=[],a=!0,c=!1;try{if(o=(r=r.call(e)).next,0===n);else for(;!(a=(t=o.call(r)).done)&&(u.push(t.value),u.length!==n);a=!0);}catch(e){c=!0,l=e}finally{try{if(!a&&null!=r.return&&(i=r.return(),Object(i)!==i))return}finally{if(c)throw l}}return u}}(n,r)||function(n,r){if(n){if("string"==typeof n)return e(n,r);var t={}.toString.call(n).slice(8,-1);return"Object"===t&&n.constructor&&(t=n.constructor.name),"Map"===t||"Set"===t?Array.from(n):"Arguments"===t||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(t)?e(n,r):void 0}}(n,r)||function(){throw new TypeError("Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}()}function o(e){var n=function(e,n){if("object"!=typeof e||!e)return e;var r=e[Symbol.toPrimitive];if(void 0!==r){var t=r.call(e,n);if("object"!=typeof t)return t;throw new TypeError("@@toPrimitive must return a primitive value.")}return String(e)}(e,"string");return"symbol"==typeof n?n:n+""}function i(e,n,r,t){return new(r||(r=Promise))(function(l,o){function i(e){try{a(t.next(e))}catch(e){o(e)}}function u(e){try{a(t.throw(e))}catch(e){o(e)}}function a(e){var n;e.done?l(e.value):(n=e.value,n instanceof r?n:new r(function(e){e(n)})).then(i,u)}a((t=t.apply(e,n||[])).next())})}"function"==typeof SuppressedError&&SuppressedError;var u=[{requestFullscreen:"requestFullscreen",exitFullscreen:"exitFullscreen",fullscreenElement:"fullscreenElement",fullscreenEnabled:"fullscreenEnabled",fullscreenchange:"fullscreenchange",fullscreenerror:"fullscreenerror"},{requestFullscreen:"webkitRequestFullscreen",exitFullscreen:"webkitExitFullscreen",fullscreenElement:"webkitFullscreenElement",fullscreenEnabled:"webkitFullscreenEnabled",fullscreenchange:"webkitfullscreenchange",fullscreenerror:"webkitfullscreenerror"},{requestFullscreen:"webkitRequestFullScreen",exitFullscreen:"webkitCancelFullScreen",fullscreenElement:"webkitCurrentFullScreenElement",fullscreenEnabled:"webkitCancelFullScreen",fullscreenchange:"webkitfullscreenchange",fullscreenerror:"webkitfullscreenerror"},{requestFullscreen:"mozRequestFullScreen",exitFullscreen:"mozCancelFullScreen",fullscreenElement:"mozFullScreenElement",fullscreenEnabled:"mozFullScreenEnabled",fullscreenchange:"mozfullscreenchange",fullscreenerror:"mozfullscreenerror"},{requestFullscreen:"msRequestFullscreen",exitFullscreen:"msExitFullscreen",fullscreenElement:"msFullscreenElement",fullscreenEnabled:"msFullscreenEnabled",fullscreenchange:"MSFullscreenChange",fullscreenerror:"MSFullscreenError"}];function a(e){var n=e.documentElement,r=e,t=u.find(function(e){return"function"==typeof n[e.requestFullscreen]&&"function"==typeof r[e.exitFullscreen]});return t?Object.freeze(Object.assign({},t)):null}var c=["position","inset","top","right","bottom","left","width","height","max-width","max-height","margin","z-index","overflow","background"],s=new WeakMap,f=/*#__PURE__*/function(){return n(function e(){!function(e,n){if(!(e instanceof n))throw new TypeError("Cannot call a class as a function")}(this,e),this.element=null,this.styles=null,this.bodyOverflow={value:"",priority:""},this.scrollX=0,this.scrollY=0,this.className="",this.addedClass=!1,this.lockedScroll=!1,this.bodyScrollLocked=!1},[{key:"enter",value:function(e){var n,r,t,o,i,u,a,f,d,v,h=e.element,b=e.document,m=e.options,y=null===(n=b.defaultView)||void 0===n?void 0:n.HTMLElement;if(!(y&&h instanceof y))throw new TypeError("CSS fallback requires an HTMLElement.");var p=s.get(b);if(p&&p!==this)throw new Error("Another CSS fullscreen fallback is already active.");s.set(b,this);try{this.element=h,this.className=null!==(r=m.fallbackClass)&&void 0!==r?r:"vue-screenfull-fallback",this.styles={};for(var E=0,k=c;E<k.length;E++){var g=k[E];this.styles[g]={value:this.element.style.getPropertyValue(g),priority:this.element.style.getPropertyPriority(g)}}this.bodyOverflow={value:null!==(o=null===(t=b.body)||void 0===t?void 0:t.style.getPropertyValue("overflow"))&&void 0!==o?o:"",priority:null!==(u=null===(i=b.body)||void 0===i?void 0:i.style.getPropertyPriority("overflow"))&&void 0!==u?u:""},this.scrollX=null!==(f=null===(a=b.defaultView)||void 0===a?void 0:a.scrollX)&&void 0!==f?f:0,this.scrollY=null!==(v=null===(d=b.defaultView)||void 0===d?void 0:d.scrollY)&&void 0!==v?v:0;for(var w=[["position","fixed"],["inset","0"],["top","0"],["right","0"],["bottom","0"],["left","0"],["width","100vw"],["height","100dvh"],["max-width","none"],["max-height","none"],["margin","0"],["z-index","2147483647"],["overflow","auto"],["background",this.element.style.background||"Canvas"]],S=0,F=w;S<F.length;S++){var O=l(F[S],2),T=O[0],R=O[1];this.element.style.setProperty(T,R,"important")}this.addedClass=!this.element.classList.contains(this.className),this.addedClass&&this.element.classList.add(this.className),this.lockedScroll=!1!==m.lockScroll,this.bodyScrollLocked=Boolean(this.lockedScroll&&b.body&&this.element!==b.documentElement&&this.element!==b.body),this.bodyScrollLocked&&b.body&&b.body.style.setProperty("overflow","hidden","important")}catch(e){try{this.exit({element:h,document:b,options:m})}finally{s.get(b)===this&&s.delete(b)}throw e}}},{key:"exit",value:function(e){var n,r,t=e.document;if(this.element&&this.styles)try{for(var l=0,o=c;l<o.length;l++){var i=o[l],u=this.styles[i];u.value?this.element.style.setProperty(i,u.value,u.priority):this.element.style.removeProperty(i)}this.addedClass&&this.element.classList.remove(this.className),this.bodyScrollLocked&&t.body&&(this.bodyOverflow.value?t.body.style.setProperty("overflow",this.bodyOverflow.value,this.bodyOverflow.priority):t.body.style.removeProperty("overflow")),this.lockedScroll&&(null===(r=null===(n=t.defaultView)||void 0===n?void 0:n.scrollTo)||void 0===r||r.call(n,this.scrollX,this.scrollY))}finally{s.get(t)===this&&s.delete(t),this.element=null,this.styles=null,this.addedClass=!1,this.lockedScroll=!1,this.bodyScrollLocked=!1}}}])}();function d(e){return e.fallback&&"none"!==e.fallback?"css"===e.fallback?new f:e.fallback:null}var v={NOT_SUPPORTED:"Enable the CSS fallback or use a browser with the Fullscreen API.",NOT_IN_BROWSER:"Call fullscreen actions after the component mounts in a browser.",USER_ACTIVATION_REQUIRED:"Call request() directly from a click, key, or touch handler.",PERMISSION_DENIED:"Check browser settings and the document Permissions Policy.",IFRAME_PERMISSION_REQUIRED:'Add allow="fullscreen" and allowfullscreen to the embedding iframe.',TARGET_NOT_CONNECTED:"Attach the target element to the current document before requesting fullscreen.",REQUEST_IN_PROGRESS:"Wait for the current fullscreen transition to finish."};function h(e,n,r){return{code:e,message:n,cause:r,recoverable:!(arguments.length>3&&void 0!==arguments[3])||arguments[3],suggestion:v[e]}}function b(e,n,r){var t,l=e instanceof Error?"".concat(e.name,": ").concat(e.message):String(e),o=l.toLowerCase(),i="exit"===n?"EXIT_FAILED":"fallback"===n?"FALLBACK_FAILED":"REQUEST_FAILED";if(o.includes("activation")||o.includes("gesture"))i="USER_ACTIVATION_REQUIRED";else if(o.includes("permission")||o.includes("denied")||o.includes("security")){var u;try{u=Boolean(null===(t=null==r?void 0:r.defaultView)||void 0===t?void 0:t.frameElement)}catch(e){u=!0}i=u?"IFRAME_PERMISSION_REQUIRED":"PERMISSION_DENIED"}return h(i,"Fullscreen ".concat(n," failed: ").concat(l),e)}var m=function(e,n){return{ok:!0,mode:e,element:n,error:null}};exports.createScreenfullController=function(){var e,n,t=this,l=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{},o=null!==(e=l.document)&&void 0!==e?e:"undefined"==typeof document?void 0:document,u=o?a(o):null,c=new Set,s=new Set,f=d(l),v=null,y=l,p=null,E=!1,k=!1,g=null,w=o?"idle":"unsupported",S=function(){return o&&u?o[u.fullscreenElement]:null},F=function(){return{isEnabled:Boolean(o&&u&&!1!==o[u.fullscreenEnabled]),isFullscreen:Boolean(S()||v),isFallback:Boolean(v),element:S()||v,status:w}},O=function(e,n){if(e)try{e(n)}catch(e){"undefined"!=typeof console&&console.error("[vue-screenfull] Listener failed.",e)}},T=null,R=F().isFullscreen,x=function(){var e=F();T&&T.isEnabled===e.isEnabled&&T.isFullscreen===e.isFullscreen&&T.isFallback===e.isFallback&&T.status===e.status&&T.element===e.element||(T=e,O(l.onChange,e),c.forEach(function(n){return O(n,e)}))},_=function(e){return g=e,arguments.length>1&&void 0!==arguments[1]&&arguments[1]||(w="NOT_SUPPORTED"===e.code||"NOT_IN_BROWSER"===e.code?"unsupported":"error"),k||(O(l.onError,e),s.forEach(function(n){return O(n,e)}),x()),l.debug&&"undefined"!=typeof console&&console.warn("[vue-screenfull]",e),{ok:!1,mode:"none",element:F().element,error:e}},I=function(){w=S()?"fullscreen":"idle";var e=F();e.isFullscreen!==R&&(e.isFullscreen?O(l.onEnter,e):O(l.onExit,e),R=e.isFullscreen),x()},P=function(e){E||_(b(e,"request",o))},N=function(e){"Escape"===e.key&&v&&D.exit()},C=function(){F().isFullscreen&&D.exit()},L=function(){var e,n,r=!1,t=new Promise(function(e){n=e}),l=function(){o&&u&&(o.removeEventListener(u.fullscreenchange,a),o.removeEventListener(u.fullscreenerror,c),void 0!==e&&globalThis.clearTimeout(e))},i=function(e){r||(r=!0,l(),n(e))},a=function(){return i({ok:!0})},c=function(e){return i({ok:!1,cause:e})};return o&&u&&(o.addEventListener(u.fullscreenchange,a),o.addEventListener(u.fullscreenerror,c),e=globalThis.setTimeout(function(){return i({ok:!1,cause:new Error("Timed out waiting for a fullscreen event.")})},3e3)),{promise:t,cleanup:l}},A=function(e){return i(t,void 0,void 0,/*#__PURE__*/r().m(function n(){var t,l,o;return r().w(function(n){for(;;)switch(n.p=n.n){case 0:if(t=L(),n.p=1,!(l=e())||"function"!=typeof l.then){n.n=3;break}return n.n=2,l;case 2:n.n=5;break;case 3:return n.n=4,t.promise;case 4:if((o=n.v).ok){n.n=5;break}throw o.cause;case 5:return n.p=5,t.cleanup(),n.f(5);case 6:return n.a(2)}},n,null,[[1,,5,6]])}))},q=function(){return i(t,void 0,void 0,/*#__PURE__*/r().m(function e(){var n;return r().w(function(e){for(;;)switch(e.n){case 0:if(o&&u&&S()){e.n=1;break}return e.a(2);case 1:return n=o[u.exitFullscreen],e.n=2,A(function(){return n.call(o)});case 2:return e.a(2)}},e)}))};function j(e,n){return i(this,void 0,void 0,/*#__PURE__*/r().m(function t(){var i,u,a,c,s,p;return r().w(function(r){for(;;)switch(r.p=r.n){case 0:if(u=null!==(i=null==n?void 0:n.fallback)&&void 0!==i?i:l.fallback,a=Object.assign(Object.assign({},l),{fallback:u}),f=d(a),o&&f){r.n=1;break}return r.a(2,_(h("NOT_SUPPORTED","The Fullscreen API is unavailable and no fallback is enabled.")));case 1:return r.p=1,y=a,r.n=2,f.enter({element:e,document:o,options:a});case 2:if(!k){r.n=4;break}return r.n=3,f.exit({element:e,document:o,options:a});case 3:return c=h("REQUEST_FAILED","The fullscreen controller was destroyed before the fallback request completed."),r.a(2,{ok:!1,mode:"none",element:null,error:c});case 4:return v=e,w="fallback",s=F(),R=!0,O(l.onFallback,s),O(l.onEnter,s),x(),r.a(2,m("fallback",e));case 5:return r.p=5,p=r.v,r.a(2,_(b(p,"fallback",o)))}},t,null,[[1,5]])}))}o&&u&&(o.addEventListener(u.fullscreenchange,I),o.addEventListener(u.fullscreenerror,P)),o&&(o.addEventListener("keydown",N),l.exitOnRouteChange&&(null===(n=o.defaultView)||void 0===n||n.addEventListener("popstate",C)));var D={get isEnabled(){return F().isEnabled},get isFullscreen(){return F().isFullscreen},get isFallback(){return F().isFallback},get element(){return F().element},get status(){return w},get error(){return g},get raw(){return u},request:function(e,n){return i(this,void 0,void 0,/*#__PURE__*/r().m(function t(){var i,a,c,s,f,d,y,g;return r().w(function(r){for(;;)switch(r.p=r.n){case 0:if(!k&&o){r.n=1;break}return r.a(2,_(h("NOT_IN_BROWSER","Fullscreen is unavailable outside a browser document.")));case 1:if(!E){r.n=2;break}return r.a(2,_(h("REQUEST_IN_PROGRESS","A fullscreen transition is already in progress."),!0));case 2:if((i=void 0===e?o.documentElement:e)&&1===i.nodeType){r.n=3;break}return r.a(2,_(h("INVALID_TARGET","The fullscreen target is not an Element.")));case 3:if(i.isConnected&&i.ownerDocument===o){r.n=4;break}return r.a(2,_(h("TARGET_NOT_CONNECTED","The fullscreen target must be connected to the current document.")));case 4:if(!F().isFullscreen){r.n=7;break}if(F().element!==i){r.n=5;break}return r.a(2,m(v?"fallback":"native",i));case 5:if(!v){r.n=7;break}return r.n=6,D.exit();case 6:if((a=r.v).ok){r.n=7;break}return r.a(2,a);case 7:if(p=!1===l.restoreFocus?null:o.activeElement,E=!0,w="requesting",x(),r.p=8,u&&D.isEnabled){r.n=10;break}return r.n=9,j(i,n);case 9:case 18:return r.a(2,r.v);case 10:return c=i[u.requestFullscreen],delete(s=Object.assign({},n)).fallback,r.n=11,A(function(){return c.call(i,s)});case 11:return k||(w=S()?"fullscreen":"idle",x()),r.a(2,m("native",S()||i));case 12:if(r.p=12,y=r.v,!k){r.n=13;break}return f=b(y,"request",o),r.a(2,{ok:!1,mode:"none",element:null,error:f});case 13:if(d=b(y,"request",o),!(null==n?void 0:n.fallback)&&!l.fallback){r.n=19;break}if(!S()){r.n=17;break}return r.p=14,r.n=15,q();case 15:r.n=17;break;case 16:return r.p=16,g=r.v,r.a(2,_(b(g,"exit",o)));case 17:return r.n=18,j(i,n);case 19:return r.a(2,_(d));case 20:return r.p=20,E=!1,r.f(20);case 21:return r.a(2)}},t,null,[[14,16],[8,12,20,21]])}))},exit:function(){return i(this,void 0,void 0,/*#__PURE__*/r().m(function e(){var n,t,i,a;return r().w(function(e){for(;;)switch(e.p=e.n){case 0:if(!k&&o){e.n=1;break}return e.a(2,_(h("NOT_IN_BROWSER","Fullscreen is unavailable outside a browser document.")));case 1:if(!E){e.n=2;break}return e.a(2,_(h("REQUEST_IN_PROGRESS","A fullscreen transition is already in progress."),!0));case 2:if(F().isFullscreen){e.n=3;break}return e.a(2,m("native",null));case 3:if(E=!0,w="exiting",x(),e.p=4,!v||!f){e.n=6;break}return t=v,e.n=5,f.exit({element:t,document:o,options:y});case 5:v=null,w="idle",i=F(),R=!1,O(l.onExit,i),x(),e.n=8;break;case 6:if(!u||!S()){e.n=8;break}return e.n=7,q();case 7:w=S()?"fullscreen":"idle",x();case 8:return null===(n=null==p?void 0:p.focus)||void 0===n||n.call(p),p=null,e.a(2,m(v?"fallback":"native",F().element));case 9:return e.p=9,a=e.v,e.a(2,_(b(a,"exit",o)));case 10:return e.p=10,E=!1,e.f(10);case 11:return e.a(2)}},e,null,[[4,9,10,11]])}))},toggle:function(e,n){return i(this,void 0,void 0,/*#__PURE__*/r().m(function t(){return r().w(function(r){for(;;)if(0===r.n)return r.a(2,F().isFullscreen?D.exit():D.request(e,n))},t)}))},on:function(e,n){"change"===e?c.add(n):s.add(n)},off:function(e,n){"change"===e?c.delete(n):s.delete(n)},clearError:function(){g=null,"error"===w&&(w=F().isFullscreen?v?"fallback":"fullscreen":"idle"),x()},destroy:function(){return i(this,void 0,void 0,/*#__PURE__*/r().m(function e(){var n,t,i;return r().w(function(e){for(;;)switch(e.p=e.n){case 0:if(!k){e.n=1;break}return e.a(2);case 1:if(k=!0,!(v&&f&&o)){e.n=6;break}return t=v,e.p=2,e.n=3,f.exit({element:t,document:o,options:y});case 3:e.n=5;break;case 4:e.p=4,i=e.v,g=b(i,"fallback",o);case 5:v=null;case 6:o&&u&&(o.removeEventListener(u.fullscreenchange,I),o.removeEventListener(u.fullscreenerror,P)),null==o||o.removeEventListener("keydown",N),l.exitOnRouteChange&&(null===(n=null==o?void 0:o.defaultView)||void 0===n||n.removeEventListener("popstate",C)),c.clear(),s.clear();case 7:return e.a(2)}},e,null,[[2,4]])}))}};return D},exports.detectFullscreenApi=a;
7
+ //# sourceMappingURL=browser.cjs.js.map