@capgo/capacitor-screen-orientation 8.3.1 → 8.4.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 +58 -13
- package/android/build.gradle +1 -0
- package/android/src/main/java/ee/forgr/capacitor/screenorientation/CapacitorScreenOrientationPlugin.java +1 -1
- package/dist/docs.json +4 -4
- package/dist/esm/definitions.d.ts +16 -3
- package/dist/esm/definitions.js.map +1 -1
- package/dist/esm/segments.d.ts +8 -0
- package/dist/esm/segments.js +26 -0
- package/dist/esm/segments.js.map +1 -0
- package/dist/esm/size-class.d.ts +2 -0
- package/dist/esm/size-class.js +33 -0
- package/dist/esm/size-class.js.map +1 -0
- package/dist/esm/web-fold.d.ts +26 -0
- package/dist/esm/web-fold.js +103 -0
- package/dist/esm/web-fold.js.map +1 -0
- package/dist/esm/web.d.ts +4 -1
- package/dist/esm/web.js +34 -35
- package/dist/esm/web.js.map +1 -1
- package/dist/plugin.cjs.js +188 -31
- package/dist/plugin.cjs.js.map +1 -1
- package/dist/plugin.js +188 -31
- package/dist/plugin.js.map +1 -1
- package/ios/Sources/CapacitorScreenOrientationPlugin/CapacitorScreenOrientationPlugin.swift +4 -18
- package/ios/Sources/CapacitorScreenOrientationPlugin/IPhoneDuoFold.swift +86 -93
- package/package.json +6 -2
package/README.md
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
<a href="https://capgo.app/?ref=plugin_screen_orientation"><img src="https://capgo.app/readme-banner.svg?repo=Cap-go/capacitor-screen-orientation" alt="Capgo - Instant updates for Capacitor" /></a>
|
|
4
4
|
|
|
5
5
|
<div align="center">
|
|
6
|
-
<p><b>Capgo</b>:
|
|
6
|
+
<p><b>Capgo</b>: push fixes to your Capacitor users in minutes, build signed iOS and Android apps without a Mac, and roll back in one click.</p>
|
|
7
7
|
<h2><a href="https://capgo.app/register/?ref=plugin_screen_orientation">➡️ Get started for free</a></h2>
|
|
8
8
|
<p>14-day unlimited free trial. No credit card required</p>
|
|
9
9
|
<p><a href="https://capgo.app/consulting/?ref=plugin_screen_orientation">Missing a feature? We'll build the plugin for you 💪</a></p>
|
|
@@ -20,28 +20,58 @@ Screen orientation plugin with support for detecting true physical device orient
|
|
|
20
20
|
- 🔒 **Detect if orientation lock is enabled** by comparing physical vs UI orientation
|
|
21
21
|
- 🔄 Real-time orientation change detection
|
|
22
22
|
- 🎯 Lock orientation to specific modes
|
|
23
|
-
- 📖 **
|
|
23
|
+
- 📖 **Foldable devices** (Galaxy Z Fold/Flip, Pixel Fold, Surface Duo, iPhone Duo): posture, hinge, size classes, and live fold updates
|
|
24
24
|
- 🌐 Web platform support
|
|
25
25
|
|
|
26
26
|
**Important Note:** This plugin can detect the physical orientation of the device using motion sensors, but it **cannot bypass the UI orientation lock**. The screen will still respect the user's orientation lock setting. This is useful for knowing how the device is physically held vs. how the UI is displayed.
|
|
27
27
|
|
|
28
|
-
##
|
|
28
|
+
## Foldable devices
|
|
29
29
|
|
|
30
|
-
|
|
30
|
+
Foldables give you more than a wider canvas: the hinge, cover screen, and posture change how people hold the phone. This plugin reports that state in JavaScript so you can adapt layouts, controls, and media without guessing from window size alone. It targets Galaxy Z Fold and Flip, Pixel Fold, Surface Duo, and iPhone Duo (iOS 27.1+), alongside the orientation APIs already in this package.
|
|
31
31
|
|
|
32
|
-
|
|
32
|
+
**What you get**
|
|
33
|
+
|
|
34
|
+
- **Device and posture**: `isDeviceFoldable()`, `getFoldState()` (`flat` / `half-opened`, `posture` `flat` / `tabletop` / `book`, hinge bounds, separating fold, occluded hinge area when applicable)
|
|
35
|
+
- **Hinge angle**: `getHingeAngle()` and `hingeAngleChange` (native sensor on Android; iPhone Duo on iOS 27.1+; `null` on web)
|
|
36
|
+
- **Layout signals**: `getSizeClass()` and `sizeClassChange` (Apple compact/regular plus Material width/height classes)
|
|
37
|
+
- **iPhone Duo extras**: `activeDisplay` (`inner` / `outer`), `getReservedRegions()`, `getBarPlacement()`, `setVerticalBarBehavior()`
|
|
38
|
+
- **Live updates**: `foldStateChange` when posture or hinge geometry changes the reported fold state (rotation alone may not fire if `devicePosture` is available but usable viewport segments are not)
|
|
39
|
+
|
|
40
|
+
**Good fits**
|
|
41
|
+
|
|
42
|
+
- Two-pane layouts that follow the hinge instead of a fixed breakpoint
|
|
43
|
+
- Toolbar, gamepad, or reader chrome that moves when the user folds to tabletop or book
|
|
44
|
+
- Cover-screen vs inner-screen flows on foldables and iPhone Duo
|
|
45
|
+
- Size-class driven UI that reacts when the user opens the device fully
|
|
46
|
+
|
|
47
|
+
**Quick start**
|
|
48
|
+
|
|
49
|
+
```typescript
|
|
50
|
+
import { ScreenOrientation } from '@capgo/capacitor-screen-orientation';
|
|
51
|
+
|
|
52
|
+
const fold = await ScreenOrientation.getFoldState();
|
|
53
|
+
console.log(fold.posture, fold.hingeBounds);
|
|
54
|
+
|
|
55
|
+
await ScreenOrientation.addListener('foldStateChange', (state) => {
|
|
56
|
+
document.documentElement.dataset.posture = state.posture;
|
|
57
|
+
});
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
**iPhone Duo (iOS 27.1+)**
|
|
61
|
+
|
|
62
|
+
| Pose | `posture` | Hinge (typical) |
|
|
33
63
|
| --- | --- | --- |
|
|
34
64
|
| Open flat, or closed on the outer display | `flat` | `180` open, `0` closed |
|
|
35
65
|
| Held half-open like a book | `book` | vertical hinge, about `20` to `160` |
|
|
36
66
|
| Propped half-open like a laptop | `tabletop` | horizontal hinge |
|
|
37
67
|
|
|
38
|
-
|
|
68
|
+
<p align="center">
|
|
69
|
+
<img src="screenshots/ios-iphone-duo.webp" alt="iPhone Duo simulator on the cover display, reporting flat posture and outer display" width="280" />
|
|
70
|
+
</p>
|
|
39
71
|
|
|
40
|
-
|
|
72
|
+
Non-folding iPhones and iOS before 27.1 stay `flat` with no hinge. Android uses Jetpack WindowManager; web uses the Device Posture API and viewport segments when the browser exposes them (hinge angle stays `null` on web).
|
|
41
73
|
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
A regular iPhone, and iOS before 27.1, stays `flat` with no hinge angle. Android foldables report posture and hinge angle the same way. Rear display and dual-screen modes stay on Android.
|
|
74
|
+
**Fold API** (full types below): `isDeviceFoldable()`, `getFoldState()`, `getHingeAngle()`, `getReservedRegions()`, `getBarPlacement()`, `setVerticalBarBehavior()`, `getSizeClass()`, listeners `foldStateChange`, `hingeAngleChange`, `sizeClassChange`.
|
|
45
75
|
|
|
46
76
|
## Documentation
|
|
47
77
|
|
|
@@ -227,6 +257,10 @@ Note: The UI will still respect the user's orientation lock setting.
|
|
|
227
257
|
Motion tracking allows you to detect how the device is physically held
|
|
228
258
|
even when the UI doesn't rotate.
|
|
229
259
|
|
|
260
|
+
On iOS 15 there is no public API to force a rotation, so the lock restricts
|
|
261
|
+
the allowed orientations and the UI rotates into them when the device
|
|
262
|
+
orientation allows it. On iOS 16 and later the rotation is requested immediately.
|
|
263
|
+
|
|
230
264
|
| Param | Type | Description |
|
|
231
265
|
| ------------- | ------------------------------------------------------------------------- | ------------------------------------ |
|
|
232
266
|
| **`options`** | <code><a href="#orientationlockoptions">OrientationLockOptions</a></code> | Options for locking the orientation. |
|
|
@@ -318,7 +352,14 @@ isDeviceFoldable() => Promise<DeviceFoldableResult>
|
|
|
318
352
|
|
|
319
353
|
Whether this device folds, and whether it can stand half-open like a laptop.
|
|
320
354
|
|
|
321
|
-
|
|
355
|
+
On web, both flags are `false` when the browser lacks fold APIs or the current reading shows
|
|
356
|
+
no fold (`devicePosture.type` is `continuous` with a single viewport segment). `foldable`
|
|
357
|
+
becomes `true` when posture is `folded` or the viewport splits into two segments.
|
|
358
|
+
On web, `supportsTabletop` reflects the current reading (for example, `false` in a book
|
|
359
|
+
pose) rather than permanent device capability.
|
|
360
|
+
|
|
361
|
+
On Android, both flags are `false` on phones that do not fold. On iOS, both are `false`
|
|
362
|
+
except on iPhone Duo (iOS 27.1 or later).
|
|
322
363
|
|
|
323
364
|
**Returns:** <code>Promise<<a href="#devicefoldableresult">DeviceFoldableResult</a>></code>
|
|
324
365
|
|
|
@@ -335,7 +376,8 @@ getFoldState() => Promise<FoldState>
|
|
|
335
376
|
|
|
336
377
|
Read the current fold.
|
|
337
378
|
|
|
338
|
-
Resolves to a flat state when the device has no fold.
|
|
379
|
+
Resolves to a flat state when the device has no fold. On web, uses
|
|
380
|
+
`navigator.devicePosture` and `window.viewport.segments` when the browser provides them.
|
|
339
381
|
|
|
340
382
|
**Returns:** <code>Promise<<a href="#foldstate">FoldState</a>></code>
|
|
341
383
|
|
|
@@ -481,7 +523,8 @@ addListener(eventName: 'hingeAngleChange', listenerFunc: (event: HingeAngleResul
|
|
|
481
523
|
Listen for hinge angle changes.
|
|
482
524
|
|
|
483
525
|
On Android the hinge sensor runs only while at least one listener is registered.
|
|
484
|
-
On iOS this fires on iPhone Duo (iOS 27.1 or later).
|
|
526
|
+
On iOS this fires on iPhone Duo (iOS 27.1 or later). On web, hinge angle stays `null`;
|
|
527
|
+
use `foldStateChange` for posture updates from the Device Posture API.
|
|
485
528
|
|
|
486
529
|
| Param | Type | Description |
|
|
487
530
|
| ------------------ | --------------------------------------------------------------------------------- | ------------------------------------------- |
|
|
@@ -735,3 +778,5 @@ Direction of the hinge relative to the window.
|
|
|
735
778
|
<code>'horizontal' | 'vertical'</code>
|
|
736
779
|
|
|
737
780
|
</docgen-api>
|
|
781
|
+
|
|
782
|
+
Foldable support adapted from [erkamyaman/capacitor-foldable](https://github.com/erkamyaman/capacitor-foldable) (MIT, Copyright (c) Erkam Yaman).
|
package/android/build.gradle
CHANGED
|
@@ -55,6 +55,7 @@ dependencies {
|
|
|
55
55
|
implementation "androidx.appcompat:appcompat:$androidxAppCompatVersion"
|
|
56
56
|
implementation "androidx.window:window-java:$androidxWindowVersion"
|
|
57
57
|
testImplementation "junit:junit:$junitVersion"
|
|
58
|
+
testImplementation 'org.robolectric:robolectric:4.16.1'
|
|
58
59
|
androidTestImplementation "androidx.test.ext:junit:$androidxJunitVersion"
|
|
59
60
|
androidTestImplementation "androidx.test.espresso:espresso-core:$androidxEspressoCoreVersion"
|
|
60
61
|
}
|
|
@@ -24,7 +24,7 @@ import org.json.JSONObject;
|
|
|
24
24
|
@CapacitorPlugin(name = "CapacitorScreenOrientation")
|
|
25
25
|
public class CapacitorScreenOrientationPlugin extends Plugin implements SensorEventListener {
|
|
26
26
|
|
|
27
|
-
private final String pluginVersion = "8.
|
|
27
|
+
private final String pluginVersion = "8.4.0";
|
|
28
28
|
private int currentOrientation;
|
|
29
29
|
private SensorManager sensorManager;
|
|
30
30
|
private Sensor accelerometer;
|
package/dist/docs.json
CHANGED
|
@@ -64,7 +64,7 @@
|
|
|
64
64
|
"text": "```typescript\n// Standard lock\nawait ScreenOrientation.lock({ orientation: 'landscape' });\n\n// Lock with motion tracking on iOS\nawait ScreenOrientation.lock({\n orientation: 'portrait',\n bypassOrientationLock: true\n});\n```"
|
|
65
65
|
}
|
|
66
66
|
],
|
|
67
|
-
"docs": "Lock the screen orientation to a specific type.\n\nLocks the screen to the specified orientation.\nOn iOS, if bypassOrientationLock is true, it will also start\ntracking physical device orientation using motion sensors.\n\nNote: The UI will still respect the user's orientation lock setting.\nMotion tracking allows you to detect how the device is physically held\neven when the UI doesn't rotate.",
|
|
67
|
+
"docs": "Lock the screen orientation to a specific type.\n\nLocks the screen to the specified orientation.\nOn iOS, if bypassOrientationLock is true, it will also start\ntracking physical device orientation using motion sensors.\n\nNote: The UI will still respect the user's orientation lock setting.\nMotion tracking allows you to detect how the device is physically held\neven when the UI doesn't rotate.\n\nOn iOS 15 there is no public API to force a rotation, so the lock restricts\nthe allowed orientations and the UI rotates into them when the device\norientation allows it. On iOS 16 and later the rotation is requested immediately.",
|
|
68
68
|
"complexTypes": [
|
|
69
69
|
"OrientationLockOptions"
|
|
70
70
|
],
|
|
@@ -195,7 +195,7 @@
|
|
|
195
195
|
"text": "```typescript\nconst { foldable, supportsTabletop } = await ScreenOrientation.isDeviceFoldable();\n```"
|
|
196
196
|
}
|
|
197
197
|
],
|
|
198
|
-
"docs": "Whether this device folds, and whether it can stand half-open like a laptop.\n\
|
|
198
|
+
"docs": "Whether this device folds, and whether it can stand half-open like a laptop.\n\nOn web, both flags are `false` when the browser lacks fold APIs or the current reading shows\nno fold (`devicePosture.type` is `continuous` with a single viewport segment). `foldable`\nbecomes `true` when posture is `folded` or the viewport splits into two segments.\nOn web, `supportsTabletop` reflects the current reading (for example, `false` in a book\npose) rather than permanent device capability.\n\nOn Android, both flags are `false` on phones that do not fold. On iOS, both are `false`\nexcept on iPhone Duo (iOS 27.1 or later).",
|
|
199
199
|
"complexTypes": [
|
|
200
200
|
"DeviceFoldableResult"
|
|
201
201
|
],
|
|
@@ -220,7 +220,7 @@
|
|
|
220
220
|
"text": "```typescript\nconst { posture, hingeOrientation } = await ScreenOrientation.getFoldState();\n```"
|
|
221
221
|
}
|
|
222
222
|
],
|
|
223
|
-
"docs": "Read the current fold.\n\nResolves to a flat state when the device has no fold.",
|
|
223
|
+
"docs": "Read the current fold.\n\nResolves to a flat state when the device has no fold. On web, uses\n`navigator.devicePosture` and `window.viewport.segments` when the browser provides them.",
|
|
224
224
|
"complexTypes": [
|
|
225
225
|
"FoldState"
|
|
226
226
|
],
|
|
@@ -446,7 +446,7 @@
|
|
|
446
446
|
"text": "A promise that resolves to a listener handle."
|
|
447
447
|
}
|
|
448
448
|
],
|
|
449
|
-
"docs": "Listen for hinge angle changes.\n\nOn Android the hinge sensor runs only while at least one listener is registered.\nOn iOS this fires on iPhone Duo (iOS 27.1 or later).
|
|
449
|
+
"docs": "Listen for hinge angle changes.\n\nOn Android the hinge sensor runs only while at least one listener is registered.\nOn iOS this fires on iPhone Duo (iOS 27.1 or later). On web, hinge angle stays `null`;\nuse `foldStateChange` for posture updates from the Device Posture API.",
|
|
450
450
|
"complexTypes": [
|
|
451
451
|
"PluginListenerHandle",
|
|
452
452
|
"HingeAngleResult"
|
|
@@ -394,6 +394,10 @@ export interface CapacitorScreenOrientationPlugin {
|
|
|
394
394
|
* Motion tracking allows you to detect how the device is physically held
|
|
395
395
|
* even when the UI doesn't rotate.
|
|
396
396
|
*
|
|
397
|
+
* On iOS 15 there is no public API to force a rotation, so the lock restricts
|
|
398
|
+
* the allowed orientations and the UI rotates into them when the device
|
|
399
|
+
* orientation allows it. On iOS 16 and later the rotation is requested immediately.
|
|
400
|
+
*
|
|
397
401
|
* @since 1.0.0
|
|
398
402
|
* @param options Options for locking the orientation.
|
|
399
403
|
* @returns {Promise<void>} A promise that resolves when the orientation is locked.
|
|
@@ -522,7 +526,14 @@ export interface CapacitorScreenOrientationPlugin {
|
|
|
522
526
|
/**
|
|
523
527
|
* Whether this device folds, and whether it can stand half-open like a laptop.
|
|
524
528
|
*
|
|
525
|
-
*
|
|
529
|
+
* On web, both flags are `false` when the browser lacks fold APIs or the current reading shows
|
|
530
|
+
* no fold (`devicePosture.type` is `continuous` with a single viewport segment). `foldable`
|
|
531
|
+
* becomes `true` when posture is `folded` or the viewport splits into two segments.
|
|
532
|
+
* On web, `supportsTabletop` reflects the current reading (for example, `false` in a book
|
|
533
|
+
* pose) rather than permanent device capability.
|
|
534
|
+
*
|
|
535
|
+
* On Android, both flags are `false` on phones that do not fold. On iOS, both are `false`
|
|
536
|
+
* except on iPhone Duo (iOS 27.1 or later).
|
|
526
537
|
*
|
|
527
538
|
* @since 8.2.0
|
|
528
539
|
* @returns {Promise<DeviceFoldableResult>} Fold capability of this device.
|
|
@@ -536,7 +547,8 @@ export interface CapacitorScreenOrientationPlugin {
|
|
|
536
547
|
/**
|
|
537
548
|
* Read the current fold.
|
|
538
549
|
*
|
|
539
|
-
* Resolves to a flat state when the device has no fold.
|
|
550
|
+
* Resolves to a flat state when the device has no fold. On web, uses
|
|
551
|
+
* `navigator.devicePosture` and `window.viewport.segments` when the browser provides them.
|
|
540
552
|
*
|
|
541
553
|
* @since 8.2.0
|
|
542
554
|
* @returns {Promise<FoldState>} The current fold state.
|
|
@@ -626,7 +638,8 @@ export interface CapacitorScreenOrientationPlugin {
|
|
|
626
638
|
* Listen for hinge angle changes.
|
|
627
639
|
*
|
|
628
640
|
* On Android the hinge sensor runs only while at least one listener is registered.
|
|
629
|
-
* On iOS this fires on iPhone Duo (iOS 27.1 or later).
|
|
641
|
+
* On iOS this fires on iPhone Duo (iOS 27.1 or later). On web, hinge angle stays `null`;
|
|
642
|
+
* use `foldStateChange` for posture updates from the Device Posture API.
|
|
630
643
|
*
|
|
631
644
|
* @since 8.2.0
|
|
632
645
|
* @param eventName The event name. Must be 'hingeAngleChange'.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"definitions.js","sourceRoot":"","sources":["../../src/definitions.ts"],"names":[],"mappings":"","sourcesContent":["import type { PluginListenerHandle } from '@capacitor/core';\n\n/**\n * Orientation type that describes the orientation state of the device.\n *\n * @since 1.0.0\n */\nexport type OrientationType = 'portrait-primary' | 'portrait-secondary' | 'landscape-primary' | 'landscape-secondary';\n\n/**\n * Orientation lock type that can be used to lock the device orientation.\n *\n * @since 1.0.0\n */\nexport type OrientationLockType =\n | 'any'\n | 'natural'\n | 'landscape'\n | 'portrait'\n | 'portrait-primary'\n | 'portrait-secondary'\n | 'landscape-primary'\n | 'landscape-secondary';\n\n/**\n * Result returned by the orientation() method.\n *\n * @since 1.0.0\n */\nexport interface ScreenOrientationResult {\n /**\n * The current orientation type.\n *\n * @since 1.0.0\n */\n type: OrientationType;\n}\n\n/**\n * Result returned by the isOrientationLocked() method.\n *\n * @since 1.0.0\n */\nexport interface OrientationLockStatusResult {\n /**\n * Whether the device orientation lock is currently enabled.\n *\n * This is determined by comparing the physical device orientation\n * (from motion sensors) with the UI orientation. If they differ,\n * orientation lock is enabled.\n *\n * Available on iOS (Core Motion) and Android (Accelerometer) when motion tracking is active.\n *\n * @since 1.0.0\n */\n locked: boolean;\n\n /**\n * The physical orientation of the device from motion sensors.\n * Available when motion tracking is active (iOS and Android).\n *\n * @since 1.0.0\n */\n physicalOrientation?: OrientationType;\n\n /**\n * The current UI orientation reported by the system.\n *\n * @since 1.0.0\n */\n uiOrientation: OrientationType;\n}\n\n/**\n * Options for locking the screen orientation.\n *\n * @since 1.0.0\n */\nexport interface OrientationLockOptions {\n /**\n * The orientation type to lock to.\n *\n * @since 1.0.0\n */\n orientation: OrientationLockType;\n\n /**\n * Whether to track physical device orientation using motion sensors.\n * When true, uses device motion sensors to detect the true physical\n * orientation of the device, even when the device orientation lock is enabled.\n *\n * **Important:** This does NOT bypass the UI orientation lock.\n * The screen will still respect the user's orientation lock setting.\n * This option only affects orientation detection/tracking - you'll receive\n * orientation change events based on how the device is physically held,\n * but the UI will not rotate if orientation lock is enabled.\n *\n * Supported on iOS (Core Motion) and Android (Accelerometer).\n *\n * @default false\n * @since 1.0.0\n */\n bypassOrientationLock?: boolean;\n}\n\n/**\n * Options for starting orientation tracking using motion sensors.\n *\n * @since 1.0.0\n */\nexport interface StartOrientationTrackingOptions {\n /**\n * Whether to track physical device orientation using motion sensors.\n * When true, uses device motion sensors to detect the true physical\n * orientation of the device, even when the device orientation lock is enabled.\n *\n * **Important:** This does NOT bypass the UI orientation lock.\n * This only enables detection of the physical orientation.\n *\n * Supported on iOS (Core Motion) and Android (Accelerometer).\n *\n * @default false\n * @since 1.0.0\n */\n bypassOrientationLock?: boolean;\n}\n\n/**\n * How open a foldable is.\n *\n * `closed` is reserved. A device shut onto its cover display reports `flat`.\n *\n * @since 8.2.0\n */\nexport type FoldStateValue = 'flat' | 'half-opened';\n\n/**\n * How a half-open foldable is held.\n *\n * `tabletop` is a horizontal hinge, like a laptop. `book` is a vertical hinge.\n *\n * @since 8.2.0\n */\nexport type FoldPosture = 'flat' | 'tabletop' | 'book';\n\n/**\n * Direction of the hinge relative to the window.\n *\n * @since 8.2.0\n */\nexport type HingeOrientation = 'horizontal' | 'vertical';\n\n/**\n * A rectangle in CSS pixels, relative to the web view.\n *\n * @since 8.2.0\n */\nexport interface FoldBounds {\n x: number;\n y: number;\n width: number;\n height: number;\n}\n\n/**\n * Current fold of the window.\n *\n * Phones that do not fold, and iOS before 27.1, resolve to a flat state.\n * iPhone Duo reports `book`, `tabletop`, or `flat`, and which display is in front.\n *\n * @since 8.2.0\n */\nexport interface FoldState {\n /**\n * Posture of the fold.\n *\n * @since 8.2.0\n */\n state: FoldStateValue;\n\n /**\n * Whether the fold splits the web view into two areas.\n *\n * @since 8.2.0\n */\n isSeparating: boolean;\n\n /**\n * How the device is held.\n *\n * @since 8.2.0\n */\n posture: FoldPosture;\n\n /**\n * Direction of the hinge. Omitted when there is no fold.\n *\n * @since 8.2.0\n */\n hingeOrientation?: HingeOrientation;\n\n /**\n * Position of the fold in CSS pixels. Omitted when there is no fold.\n *\n * @since 8.2.0\n */\n hingeBounds?: FoldBounds;\n\n /**\n * Area the hinge covers. Present when the hinge has a physical gap.\n *\n * @since 8.2.0\n */\n occludedBounds?: FoldBounds;\n\n /**\n * Which display is showing the app on iPhone Duo. Omitted on Android, web, and iOS before 27.1.\n *\n * @since 8.2.0\n */\n activeDisplay?: 'inner' | 'outer';\n\n /**\n * Space the system keeps clear around the fold, in CSS pixels. iPhone Duo reports 20 on each side of a vertical fold.\n *\n * @since 8.2.0\n */\n hingeMargins?: { top: number; right: number; bottom: number; left: number };\n\n /**\n * Areas covering the display, such as the iPhone Duo camera. Omitted when there are none.\n *\n * @since 8.2.0\n */\n cameraBounds?: FoldBounds[];\n}\n\n/**\n * Whether this device can fold.\n *\n * @since 8.2.0\n */\nexport interface DeviceFoldableResult {\n /**\n * Whether the device has a fold.\n *\n * @since 8.2.0\n */\n foldable: boolean;\n\n /**\n * Whether it can stand half-open like a laptop.\n *\n * @since 8.2.0\n */\n supportsTabletop: boolean;\n}\n\n/**\n * Angle between the two halves of a foldable, in degrees.\n *\n * `0` is closed and `180` is flat. `angle` is `null` when the device has no hinge sensor.\n *\n * @since 8.2.0\n */\nexport interface HingeAngleResult {\n /**\n * Hinge angle in degrees, or `null` when no sensor is available.\n *\n * @since 8.2.0\n */\n angle: number | null;\n\n /**\n * How far open iPhone Duo is, as the system sees it. `null` on Android and web.\n *\n * @since 8.2.0\n */\n status?: 'closed' | 'partiallyOpen' | 'fullyOpen' | null;\n}\n\n/**\n * A region the system reserves on iPhone Duo.\n *\n * `division` is the fold. `occlusion` is something covering the display, such as the camera.\n *\n * @since 8.2.0\n */\nexport interface ReservedRegion {\n /**\n * What the region is.\n *\n * @since 8.2.0\n */\n kind: 'division' | 'occlusion';\n\n /**\n * Whether the region applies right now. An inactive division is a flat fold.\n *\n * @since 8.2.0\n */\n isActive: boolean;\n\n /**\n * Left edge, in CSS pixels.\n *\n * @since 8.2.0\n */\n x: number;\n\n /**\n * Top edge, in CSS pixels.\n *\n * @since 8.2.0\n */\n y: number;\n\n /**\n * Width in CSS pixels.\n *\n * @since 8.2.0\n */\n width: number;\n\n /**\n * Height in CSS pixels.\n *\n * @since 8.2.0\n */\n height: number;\n\n /**\n * Space to keep clear around the region, in CSS pixels.\n *\n * @since 8.2.0\n */\n margins: { top: number; right: number; bottom: number; left: number };\n}\n\n/**\n * Where iPhone Duo places native bars.\n *\n * @since 8.2.0\n */\nexport interface BarPlacement {\n /**\n * The edge the system moves tab bars and toolbars to. `null` when they stay horizontal.\n *\n * @since 8.2.0\n */\n verticalBarEdge: 'leading' | 'trailing' | null;\n\n /**\n * How much room the vertical bar takes, in points. `0` when bars stay horizontal.\n *\n * @since 8.2.0\n */\n inset: number;\n}\n\n/**\n * Window size classes.\n *\n * `horizontal` and `vertical` follow Apple's compact/regular split.\n * On Android and web, `regular` starts at 600 CSS pixels wide and 480 tall.\n * `widthClass` and `heightClass` follow Material window size classes.\n *\n * @since 8.2.0\n */\nexport interface SizeClass {\n /**\n * Width size class. `compact` on a phone, `regular` on the inner display of a foldable, a tablet, or a window at least 600 CSS pixels wide.\n *\n * @since 8.2.0\n */\n horizontal: 'compact' | 'regular';\n\n /**\n * Height size class. `regular` starts at 480 CSS pixels.\n *\n * @since 8.2.0\n */\n vertical: 'compact' | 'regular';\n\n /**\n * Material window width class.\n *\n * @since 8.2.0\n */\n widthClass: 'compact' | 'medium' | 'expanded' | 'large' | 'extraLarge';\n\n /**\n * Material window height class.\n *\n * @since 8.2.0\n */\n heightClass: 'compact' | 'medium' | 'expanded';\n}\n\n/**\n * Capacitor Screen Orientation Plugin interface.\n *\n * Provides methods to detect and control screen orientation,\n * with support for detecting true physical device orientation using motion sensors.\n *\n * @since 1.0.0\n */\nexport interface CapacitorScreenOrientationPlugin {\n /**\n * Get the current screen orientation.\n *\n * Returns the current orientation of the device screen.\n *\n * @since 1.0.0\n * @returns {Promise<ScreenOrientationResult>} A promise that resolves with the current orientation.\n *\n * @example\n * ```typescript\n * const result = await ScreenOrientation.orientation();\n * console.log('Current orientation:', result.type);\n * ```\n */\n orientation(): Promise<ScreenOrientationResult>;\n\n /**\n * Lock the screen orientation to a specific type.\n *\n * Locks the screen to the specified orientation.\n * On iOS, if bypassOrientationLock is true, it will also start\n * tracking physical device orientation using motion sensors.\n *\n * Note: The UI will still respect the user's orientation lock setting.\n * Motion tracking allows you to detect how the device is physically held\n * even when the UI doesn't rotate.\n *\n * @since 1.0.0\n * @param options Options for locking the orientation.\n * @returns {Promise<void>} A promise that resolves when the orientation is locked.\n *\n * @example\n * ```typescript\n * // Standard lock\n * await ScreenOrientation.lock({ orientation: 'landscape' });\n *\n * // Lock with motion tracking on iOS\n * await ScreenOrientation.lock({\n * orientation: 'portrait',\n * bypassOrientationLock: true\n * });\n * ```\n */\n lock(options: OrientationLockOptions): Promise<void>;\n\n /**\n * Unlock the screen orientation.\n *\n * Allows the screen to rotate freely based on device position.\n * Also stops any motion-based orientation tracking if it was enabled.\n *\n * @since 1.0.0\n * @returns {Promise<void>} A promise that resolves when the orientation is unlocked.\n *\n * @example\n * ```typescript\n * await ScreenOrientation.unlock();\n * ```\n */\n unlock(): Promise<void>;\n\n /**\n * Start tracking device orientation using motion sensors.\n *\n * This method is useful when you want to track the device's physical\n * orientation independently from the screen orientation lock.\n * It uses Core Motion on iOS to detect orientation changes.\n *\n * @since 1.0.0\n * @param options Options for starting orientation tracking.\n * @returns {Promise<void>} A promise that resolves when tracking starts.\n *\n * @example\n * ```typescript\n * await ScreenOrientation.startOrientationTracking({\n * bypassOrientationLock: true\n * });\n *\n * // Listen for changes\n * ScreenOrientation.addListener('screenOrientationChange', (result) => {\n * console.log('Orientation changed:', result.type);\n * });\n * ```\n */\n startOrientationTracking(options?: StartOrientationTrackingOptions): Promise<void>;\n\n /**\n * Stop tracking device orientation using motion sensors.\n *\n * Stops the motion-based orientation tracking if it was started.\n *\n * @since 1.0.0\n * @returns {Promise<void>} A promise that resolves when tracking stops.\n *\n * @example\n * ```typescript\n * await ScreenOrientation.stopOrientationTracking();\n * ```\n */\n stopOrientationTracking(): Promise<void>;\n\n /**\n * Check if device orientation lock is currently enabled.\n *\n * This method compares the physical device orientation (from motion sensors)\n * with the UI orientation. If they differ, orientation lock is enabled.\n *\n * Note: This requires motion tracking to be active via\n * startOrientationTracking() or lock() with bypassOrientationLock: true.\n * Works on both iOS (Core Motion) and Android (Accelerometer).\n *\n * @since 1.0.0\n * @returns {Promise<OrientationLockStatusResult>} A promise that resolves with the lock status.\n *\n * @example\n * ```typescript\n * // Start motion tracking first\n * await ScreenOrientation.startOrientationTracking({\n * bypassOrientationLock: true\n * });\n *\n * // Check lock status\n * const status = await ScreenOrientation.isOrientationLocked();\n * if (status.locked) {\n * console.log('Orientation lock is ON');\n * console.log('Physical:', status.physicalOrientation);\n * console.log('UI:', status.uiOrientation);\n * }\n * ```\n */\n isOrientationLocked(): Promise<OrientationLockStatusResult>;\n\n /**\n * Listen for screen orientation changes.\n *\n * Registers a listener that will be called whenever the screen orientation changes.\n * If motion-based tracking is enabled, this will also fire for orientation changes\n * detected by motion sensors even when orientation lock is enabled.\n *\n * @since 1.0.0\n * @param eventName The event name. Must be 'screenOrientationChange'.\n * @param listenerFunc Callback function invoked when orientation changes.\n * @returns {Promise<PluginListenerHandle>} A promise that resolves to a listener handle.\n *\n * @example\n * ```typescript\n * const listener = await ScreenOrientation.addListener(\n * 'screenOrientationChange',\n * (result) => {\n * console.log('New orientation:', result.type);\n * }\n * );\n *\n * // To remove the listener:\n * await listener.remove();\n * ```\n */\n /**\n * Whether this device folds, and whether it can stand half-open like a laptop.\n *\n * Both flags are `false` on web, on Android phones that do not fold, and on iOS except iPhone Duo (iOS 27.1 or later).\n *\n * @since 8.2.0\n * @returns {Promise<DeviceFoldableResult>} Fold capability of this device.\n *\n * @example\n * ```typescript\n * const { foldable, supportsTabletop } = await ScreenOrientation.isDeviceFoldable();\n * ```\n */\n isDeviceFoldable(): Promise<DeviceFoldableResult>;\n\n /**\n * Read the current fold.\n *\n * Resolves to a flat state when the device has no fold.\n *\n * @since 8.2.0\n * @returns {Promise<FoldState>} The current fold state.\n *\n * @example\n * ```typescript\n * const { posture, hingeOrientation } = await ScreenOrientation.getFoldState();\n * ```\n */\n getFoldState(): Promise<FoldState>;\n\n /**\n * Read the hinge angle in degrees.\n *\n * `0` is closed and `180` is flat. `angle` is `null` without a hinge sensor.\n *\n * @since 8.2.0\n * @returns {Promise<HingeAngleResult>} The latest hinge angle.\n *\n * @example\n * ```typescript\n * const { angle } = await ScreenOrientation.getHingeAngle();\n * ```\n */\n getHingeAngle(): Promise<HingeAngleResult>;\n\n /**\n * Read the fold and anything covering the screen.\n *\n * iPhone Duo reports the fold, the vertical status bar area, and the under-display camera.\n * Resolves to an empty list on Android, web, and iOS before 27.1.\n *\n * @since 8.2.0\n * @returns {Promise<{ regions: ReservedRegion[] }>} The reserved regions.\n */\n getReservedRegions(): Promise<{ regions: ReservedRegion[] }>;\n\n /**\n * Read where iPhone Duo puts native tab bars and toolbars.\n *\n * `verticalBarEdge` is `null` when bars stay horizontal, and always on Android and web.\n *\n * @since 8.2.0\n * @returns {Promise<BarPlacement>} The current bar placement.\n */\n getBarPlacement(): Promise<BarPlacement>;\n\n /**\n * Choose whether iPhone Duo may move this app's bars to the side.\n *\n * Resolves to `{ applied: false }` unless the app's bridge view controller opts in.\n * Android and web always resolve to `{ applied: false }`.\n *\n * @since 8.2.0\n * @param options `automatic` lets the system move bars. `disabled` keeps them horizontal.\n * @returns {Promise<{ applied: boolean }>} Whether the app applied the choice.\n */\n setVerticalBarBehavior(options: { behavior: 'automatic' | 'disabled' }): Promise<{ applied: boolean }>;\n\n /**\n * Read the window size classes.\n *\n * @since 8.2.0\n * @returns {Promise<SizeClass>} Apple and Material size classes for the current window.\n *\n * @example\n * ```typescript\n * const { horizontal, widthClass } = await ScreenOrientation.getSizeClass();\n * ```\n */\n getSizeClass(): Promise<SizeClass>;\n\n addListener(\n eventName: 'screenOrientationChange',\n listenerFunc: (result: ScreenOrientationResult) => void,\n ): Promise<PluginListenerHandle>;\n\n /**\n * Listen for fold changes.\n *\n * On a foldable this also fires when the device rotates, because the hinge\n * bounds rotate with the window.\n *\n * @since 8.2.0\n * @param eventName The event name. Must be 'foldStateChange'.\n * @param listenerFunc Callback invoked with the new fold state.\n * @returns {Promise<PluginListenerHandle>} A promise that resolves to a listener handle.\n */\n addListener(eventName: 'foldStateChange', listenerFunc: (state: FoldState) => void): Promise<PluginListenerHandle>;\n\n /**\n * Listen for hinge angle changes.\n *\n * On Android the hinge sensor runs only while at least one listener is registered.\n * On iOS this fires on iPhone Duo (iOS 27.1 or later). Never fires on web.\n *\n * @since 8.2.0\n * @param eventName The event name. Must be 'hingeAngleChange'.\n * @param listenerFunc Callback invoked with the angle in degrees.\n * @returns {Promise<PluginListenerHandle>} A promise that resolves to a listener handle.\n */\n addListener(\n eventName: 'hingeAngleChange',\n listenerFunc: (event: HingeAngleResult) => void,\n ): Promise<PluginListenerHandle>;\n\n /**\n * Listen for size class changes, such as unfolding, rotating, or resizing.\n *\n * @since 8.2.0\n * @param eventName The event name. Must be 'sizeClassChange'.\n * @param listenerFunc Callback invoked with the new size class.\n * @returns {Promise<PluginListenerHandle>} A promise that resolves to a listener handle.\n */\n addListener(\n eventName: 'sizeClassChange',\n listenerFunc: (sizeClass: SizeClass) => void,\n ): Promise<PluginListenerHandle>;\n\n /**\n * Remove all listeners for this plugin.\n *\n * Removes all registered event listeners.\n *\n * @since 1.0.0\n * @returns {Promise<void>} A promise that resolves when all listeners are removed.\n *\n * @example\n * ```typescript\n * await ScreenOrientation.removeAllListeners();\n * ```\n */\n removeAllListeners(): Promise<void>;\n\n /**\n * Get the native plugin version.\n *\n * Returns the current version of the native plugin implementation.\n *\n * @since 1.0.0\n * @returns {Promise<{ version: string }>} A promise that resolves with the version string.\n *\n * @example\n * ```typescript\n * const { version } = await ScreenOrientation.getPluginVersion();\n * console.log('Plugin version:', version);\n * ```\n */\n getPluginVersion(): Promise<{ version: string }>;\n}\n"]}
|
|
1
|
+
{"version":3,"file":"definitions.js","sourceRoot":"","sources":["../../src/definitions.ts"],"names":[],"mappings":"","sourcesContent":["import type { PluginListenerHandle } from '@capacitor/core';\n\n/**\n * Orientation type that describes the orientation state of the device.\n *\n * @since 1.0.0\n */\nexport type OrientationType = 'portrait-primary' | 'portrait-secondary' | 'landscape-primary' | 'landscape-secondary';\n\n/**\n * Orientation lock type that can be used to lock the device orientation.\n *\n * @since 1.0.0\n */\nexport type OrientationLockType =\n | 'any'\n | 'natural'\n | 'landscape'\n | 'portrait'\n | 'portrait-primary'\n | 'portrait-secondary'\n | 'landscape-primary'\n | 'landscape-secondary';\n\n/**\n * Result returned by the orientation() method.\n *\n * @since 1.0.0\n */\nexport interface ScreenOrientationResult {\n /**\n * The current orientation type.\n *\n * @since 1.0.0\n */\n type: OrientationType;\n}\n\n/**\n * Result returned by the isOrientationLocked() method.\n *\n * @since 1.0.0\n */\nexport interface OrientationLockStatusResult {\n /**\n * Whether the device orientation lock is currently enabled.\n *\n * This is determined by comparing the physical device orientation\n * (from motion sensors) with the UI orientation. If they differ,\n * orientation lock is enabled.\n *\n * Available on iOS (Core Motion) and Android (Accelerometer) when motion tracking is active.\n *\n * @since 1.0.0\n */\n locked: boolean;\n\n /**\n * The physical orientation of the device from motion sensors.\n * Available when motion tracking is active (iOS and Android).\n *\n * @since 1.0.0\n */\n physicalOrientation?: OrientationType;\n\n /**\n * The current UI orientation reported by the system.\n *\n * @since 1.0.0\n */\n uiOrientation: OrientationType;\n}\n\n/**\n * Options for locking the screen orientation.\n *\n * @since 1.0.0\n */\nexport interface OrientationLockOptions {\n /**\n * The orientation type to lock to.\n *\n * @since 1.0.0\n */\n orientation: OrientationLockType;\n\n /**\n * Whether to track physical device orientation using motion sensors.\n * When true, uses device motion sensors to detect the true physical\n * orientation of the device, even when the device orientation lock is enabled.\n *\n * **Important:** This does NOT bypass the UI orientation lock.\n * The screen will still respect the user's orientation lock setting.\n * This option only affects orientation detection/tracking - you'll receive\n * orientation change events based on how the device is physically held,\n * but the UI will not rotate if orientation lock is enabled.\n *\n * Supported on iOS (Core Motion) and Android (Accelerometer).\n *\n * @default false\n * @since 1.0.0\n */\n bypassOrientationLock?: boolean;\n}\n\n/**\n * Options for starting orientation tracking using motion sensors.\n *\n * @since 1.0.0\n */\nexport interface StartOrientationTrackingOptions {\n /**\n * Whether to track physical device orientation using motion sensors.\n * When true, uses device motion sensors to detect the true physical\n * orientation of the device, even when the device orientation lock is enabled.\n *\n * **Important:** This does NOT bypass the UI orientation lock.\n * This only enables detection of the physical orientation.\n *\n * Supported on iOS (Core Motion) and Android (Accelerometer).\n *\n * @default false\n * @since 1.0.0\n */\n bypassOrientationLock?: boolean;\n}\n\n/**\n * How open a foldable is.\n *\n * `closed` is reserved. A device shut onto its cover display reports `flat`.\n *\n * @since 8.2.0\n */\nexport type FoldStateValue = 'flat' | 'half-opened';\n\n/**\n * How a half-open foldable is held.\n *\n * `tabletop` is a horizontal hinge, like a laptop. `book` is a vertical hinge.\n *\n * @since 8.2.0\n */\nexport type FoldPosture = 'flat' | 'tabletop' | 'book';\n\n/**\n * Direction of the hinge relative to the window.\n *\n * @since 8.2.0\n */\nexport type HingeOrientation = 'horizontal' | 'vertical';\n\n/**\n * A rectangle in CSS pixels, relative to the web view.\n *\n * @since 8.2.0\n */\nexport interface FoldBounds {\n x: number;\n y: number;\n width: number;\n height: number;\n}\n\n/**\n * Current fold of the window.\n *\n * Phones that do not fold, and iOS before 27.1, resolve to a flat state.\n * iPhone Duo reports `book`, `tabletop`, or `flat`, and which display is in front.\n *\n * @since 8.2.0\n */\nexport interface FoldState {\n /**\n * Posture of the fold.\n *\n * @since 8.2.0\n */\n state: FoldStateValue;\n\n /**\n * Whether the fold splits the web view into two areas.\n *\n * @since 8.2.0\n */\n isSeparating: boolean;\n\n /**\n * How the device is held.\n *\n * @since 8.2.0\n */\n posture: FoldPosture;\n\n /**\n * Direction of the hinge. Omitted when there is no fold.\n *\n * @since 8.2.0\n */\n hingeOrientation?: HingeOrientation;\n\n /**\n * Position of the fold in CSS pixels. Omitted when there is no fold.\n *\n * @since 8.2.0\n */\n hingeBounds?: FoldBounds;\n\n /**\n * Area the hinge covers. Present when the hinge has a physical gap.\n *\n * @since 8.2.0\n */\n occludedBounds?: FoldBounds;\n\n /**\n * Which display is showing the app on iPhone Duo. Omitted on Android, web, and iOS before 27.1.\n *\n * @since 8.2.0\n */\n activeDisplay?: 'inner' | 'outer';\n\n /**\n * Space the system keeps clear around the fold, in CSS pixels. iPhone Duo reports 20 on each side of a vertical fold.\n *\n * @since 8.2.0\n */\n hingeMargins?: { top: number; right: number; bottom: number; left: number };\n\n /**\n * Areas covering the display, such as the iPhone Duo camera. Omitted when there are none.\n *\n * @since 8.2.0\n */\n cameraBounds?: FoldBounds[];\n}\n\n/**\n * Whether this device can fold.\n *\n * @since 8.2.0\n */\nexport interface DeviceFoldableResult {\n /**\n * Whether the device has a fold.\n *\n * @since 8.2.0\n */\n foldable: boolean;\n\n /**\n * Whether it can stand half-open like a laptop.\n *\n * @since 8.2.0\n */\n supportsTabletop: boolean;\n}\n\n/**\n * Angle between the two halves of a foldable, in degrees.\n *\n * `0` is closed and `180` is flat. `angle` is `null` when the device has no hinge sensor.\n *\n * @since 8.2.0\n */\nexport interface HingeAngleResult {\n /**\n * Hinge angle in degrees, or `null` when no sensor is available.\n *\n * @since 8.2.0\n */\n angle: number | null;\n\n /**\n * How far open iPhone Duo is, as the system sees it. `null` on Android and web.\n *\n * @since 8.2.0\n */\n status?: 'closed' | 'partiallyOpen' | 'fullyOpen' | null;\n}\n\n/**\n * A region the system reserves on iPhone Duo.\n *\n * `division` is the fold. `occlusion` is something covering the display, such as the camera.\n *\n * @since 8.2.0\n */\nexport interface ReservedRegion {\n /**\n * What the region is.\n *\n * @since 8.2.0\n */\n kind: 'division' | 'occlusion';\n\n /**\n * Whether the region applies right now. An inactive division is a flat fold.\n *\n * @since 8.2.0\n */\n isActive: boolean;\n\n /**\n * Left edge, in CSS pixels.\n *\n * @since 8.2.0\n */\n x: number;\n\n /**\n * Top edge, in CSS pixels.\n *\n * @since 8.2.0\n */\n y: number;\n\n /**\n * Width in CSS pixels.\n *\n * @since 8.2.0\n */\n width: number;\n\n /**\n * Height in CSS pixels.\n *\n * @since 8.2.0\n */\n height: number;\n\n /**\n * Space to keep clear around the region, in CSS pixels.\n *\n * @since 8.2.0\n */\n margins: { top: number; right: number; bottom: number; left: number };\n}\n\n/**\n * Where iPhone Duo places native bars.\n *\n * @since 8.2.0\n */\nexport interface BarPlacement {\n /**\n * The edge the system moves tab bars and toolbars to. `null` when they stay horizontal.\n *\n * @since 8.2.0\n */\n verticalBarEdge: 'leading' | 'trailing' | null;\n\n /**\n * How much room the vertical bar takes, in points. `0` when bars stay horizontal.\n *\n * @since 8.2.0\n */\n inset: number;\n}\n\n/**\n * Window size classes.\n *\n * `horizontal` and `vertical` follow Apple's compact/regular split.\n * On Android and web, `regular` starts at 600 CSS pixels wide and 480 tall.\n * `widthClass` and `heightClass` follow Material window size classes.\n *\n * @since 8.2.0\n */\nexport interface SizeClass {\n /**\n * Width size class. `compact` on a phone, `regular` on the inner display of a foldable, a tablet, or a window at least 600 CSS pixels wide.\n *\n * @since 8.2.0\n */\n horizontal: 'compact' | 'regular';\n\n /**\n * Height size class. `regular` starts at 480 CSS pixels.\n *\n * @since 8.2.0\n */\n vertical: 'compact' | 'regular';\n\n /**\n * Material window width class.\n *\n * @since 8.2.0\n */\n widthClass: 'compact' | 'medium' | 'expanded' | 'large' | 'extraLarge';\n\n /**\n * Material window height class.\n *\n * @since 8.2.0\n */\n heightClass: 'compact' | 'medium' | 'expanded';\n}\n\n/**\n * Capacitor Screen Orientation Plugin interface.\n *\n * Provides methods to detect and control screen orientation,\n * with support for detecting true physical device orientation using motion sensors.\n *\n * @since 1.0.0\n */\nexport interface CapacitorScreenOrientationPlugin {\n /**\n * Get the current screen orientation.\n *\n * Returns the current orientation of the device screen.\n *\n * @since 1.0.0\n * @returns {Promise<ScreenOrientationResult>} A promise that resolves with the current orientation.\n *\n * @example\n * ```typescript\n * const result = await ScreenOrientation.orientation();\n * console.log('Current orientation:', result.type);\n * ```\n */\n orientation(): Promise<ScreenOrientationResult>;\n\n /**\n * Lock the screen orientation to a specific type.\n *\n * Locks the screen to the specified orientation.\n * On iOS, if bypassOrientationLock is true, it will also start\n * tracking physical device orientation using motion sensors.\n *\n * Note: The UI will still respect the user's orientation lock setting.\n * Motion tracking allows you to detect how the device is physically held\n * even when the UI doesn't rotate.\n *\n * On iOS 15 there is no public API to force a rotation, so the lock restricts\n * the allowed orientations and the UI rotates into them when the device\n * orientation allows it. On iOS 16 and later the rotation is requested immediately.\n *\n * @since 1.0.0\n * @param options Options for locking the orientation.\n * @returns {Promise<void>} A promise that resolves when the orientation is locked.\n *\n * @example\n * ```typescript\n * // Standard lock\n * await ScreenOrientation.lock({ orientation: 'landscape' });\n *\n * // Lock with motion tracking on iOS\n * await ScreenOrientation.lock({\n * orientation: 'portrait',\n * bypassOrientationLock: true\n * });\n * ```\n */\n lock(options: OrientationLockOptions): Promise<void>;\n\n /**\n * Unlock the screen orientation.\n *\n * Allows the screen to rotate freely based on device position.\n * Also stops any motion-based orientation tracking if it was enabled.\n *\n * @since 1.0.0\n * @returns {Promise<void>} A promise that resolves when the orientation is unlocked.\n *\n * @example\n * ```typescript\n * await ScreenOrientation.unlock();\n * ```\n */\n unlock(): Promise<void>;\n\n /**\n * Start tracking device orientation using motion sensors.\n *\n * This method is useful when you want to track the device's physical\n * orientation independently from the screen orientation lock.\n * It uses Core Motion on iOS to detect orientation changes.\n *\n * @since 1.0.0\n * @param options Options for starting orientation tracking.\n * @returns {Promise<void>} A promise that resolves when tracking starts.\n *\n * @example\n * ```typescript\n * await ScreenOrientation.startOrientationTracking({\n * bypassOrientationLock: true\n * });\n *\n * // Listen for changes\n * ScreenOrientation.addListener('screenOrientationChange', (result) => {\n * console.log('Orientation changed:', result.type);\n * });\n * ```\n */\n startOrientationTracking(options?: StartOrientationTrackingOptions): Promise<void>;\n\n /**\n * Stop tracking device orientation using motion sensors.\n *\n * Stops the motion-based orientation tracking if it was started.\n *\n * @since 1.0.0\n * @returns {Promise<void>} A promise that resolves when tracking stops.\n *\n * @example\n * ```typescript\n * await ScreenOrientation.stopOrientationTracking();\n * ```\n */\n stopOrientationTracking(): Promise<void>;\n\n /**\n * Check if device orientation lock is currently enabled.\n *\n * This method compares the physical device orientation (from motion sensors)\n * with the UI orientation. If they differ, orientation lock is enabled.\n *\n * Note: This requires motion tracking to be active via\n * startOrientationTracking() or lock() with bypassOrientationLock: true.\n * Works on both iOS (Core Motion) and Android (Accelerometer).\n *\n * @since 1.0.0\n * @returns {Promise<OrientationLockStatusResult>} A promise that resolves with the lock status.\n *\n * @example\n * ```typescript\n * // Start motion tracking first\n * await ScreenOrientation.startOrientationTracking({\n * bypassOrientationLock: true\n * });\n *\n * // Check lock status\n * const status = await ScreenOrientation.isOrientationLocked();\n * if (status.locked) {\n * console.log('Orientation lock is ON');\n * console.log('Physical:', status.physicalOrientation);\n * console.log('UI:', status.uiOrientation);\n * }\n * ```\n */\n isOrientationLocked(): Promise<OrientationLockStatusResult>;\n\n /**\n * Listen for screen orientation changes.\n *\n * Registers a listener that will be called whenever the screen orientation changes.\n * If motion-based tracking is enabled, this will also fire for orientation changes\n * detected by motion sensors even when orientation lock is enabled.\n *\n * @since 1.0.0\n * @param eventName The event name. Must be 'screenOrientationChange'.\n * @param listenerFunc Callback function invoked when orientation changes.\n * @returns {Promise<PluginListenerHandle>} A promise that resolves to a listener handle.\n *\n * @example\n * ```typescript\n * const listener = await ScreenOrientation.addListener(\n * 'screenOrientationChange',\n * (result) => {\n * console.log('New orientation:', result.type);\n * }\n * );\n *\n * // To remove the listener:\n * await listener.remove();\n * ```\n */\n /**\n * Whether this device folds, and whether it can stand half-open like a laptop.\n *\n * On web, both flags are `false` when the browser lacks fold APIs or the current reading shows\n * no fold (`devicePosture.type` is `continuous` with a single viewport segment). `foldable`\n * becomes `true` when posture is `folded` or the viewport splits into two segments.\n * On web, `supportsTabletop` reflects the current reading (for example, `false` in a book\n * pose) rather than permanent device capability.\n *\n * On Android, both flags are `false` on phones that do not fold. On iOS, both are `false`\n * except on iPhone Duo (iOS 27.1 or later).\n *\n * @since 8.2.0\n * @returns {Promise<DeviceFoldableResult>} Fold capability of this device.\n *\n * @example\n * ```typescript\n * const { foldable, supportsTabletop } = await ScreenOrientation.isDeviceFoldable();\n * ```\n */\n isDeviceFoldable(): Promise<DeviceFoldableResult>;\n\n /**\n * Read the current fold.\n *\n * Resolves to a flat state when the device has no fold. On web, uses\n * `navigator.devicePosture` and `window.viewport.segments` when the browser provides them.\n *\n * @since 8.2.0\n * @returns {Promise<FoldState>} The current fold state.\n *\n * @example\n * ```typescript\n * const { posture, hingeOrientation } = await ScreenOrientation.getFoldState();\n * ```\n */\n getFoldState(): Promise<FoldState>;\n\n /**\n * Read the hinge angle in degrees.\n *\n * `0` is closed and `180` is flat. `angle` is `null` without a hinge sensor.\n *\n * @since 8.2.0\n * @returns {Promise<HingeAngleResult>} The latest hinge angle.\n *\n * @example\n * ```typescript\n * const { angle } = await ScreenOrientation.getHingeAngle();\n * ```\n */\n getHingeAngle(): Promise<HingeAngleResult>;\n\n /**\n * Read the fold and anything covering the screen.\n *\n * iPhone Duo reports the fold, the vertical status bar area, and the under-display camera.\n * Resolves to an empty list on Android, web, and iOS before 27.1.\n *\n * @since 8.2.0\n * @returns {Promise<{ regions: ReservedRegion[] }>} The reserved regions.\n */\n getReservedRegions(): Promise<{ regions: ReservedRegion[] }>;\n\n /**\n * Read where iPhone Duo puts native tab bars and toolbars.\n *\n * `verticalBarEdge` is `null` when bars stay horizontal, and always on Android and web.\n *\n * @since 8.2.0\n * @returns {Promise<BarPlacement>} The current bar placement.\n */\n getBarPlacement(): Promise<BarPlacement>;\n\n /**\n * Choose whether iPhone Duo may move this app's bars to the side.\n *\n * Resolves to `{ applied: false }` unless the app's bridge view controller opts in.\n * Android and web always resolve to `{ applied: false }`.\n *\n * @since 8.2.0\n * @param options `automatic` lets the system move bars. `disabled` keeps them horizontal.\n * @returns {Promise<{ applied: boolean }>} Whether the app applied the choice.\n */\n setVerticalBarBehavior(options: { behavior: 'automatic' | 'disabled' }): Promise<{ applied: boolean }>;\n\n /**\n * Read the window size classes.\n *\n * @since 8.2.0\n * @returns {Promise<SizeClass>} Apple and Material size classes for the current window.\n *\n * @example\n * ```typescript\n * const { horizontal, widthClass } = await ScreenOrientation.getSizeClass();\n * ```\n */\n getSizeClass(): Promise<SizeClass>;\n\n addListener(\n eventName: 'screenOrientationChange',\n listenerFunc: (result: ScreenOrientationResult) => void,\n ): Promise<PluginListenerHandle>;\n\n /**\n * Listen for fold changes.\n *\n * On a foldable this also fires when the device rotates, because the hinge\n * bounds rotate with the window.\n *\n * @since 8.2.0\n * @param eventName The event name. Must be 'foldStateChange'.\n * @param listenerFunc Callback invoked with the new fold state.\n * @returns {Promise<PluginListenerHandle>} A promise that resolves to a listener handle.\n */\n addListener(eventName: 'foldStateChange', listenerFunc: (state: FoldState) => void): Promise<PluginListenerHandle>;\n\n /**\n * Listen for hinge angle changes.\n *\n * On Android the hinge sensor runs only while at least one listener is registered.\n * On iOS this fires on iPhone Duo (iOS 27.1 or later). On web, hinge angle stays `null`;\n * use `foldStateChange` for posture updates from the Device Posture API.\n *\n * @since 8.2.0\n * @param eventName The event name. Must be 'hingeAngleChange'.\n * @param listenerFunc Callback invoked with the angle in degrees.\n * @returns {Promise<PluginListenerHandle>} A promise that resolves to a listener handle.\n */\n addListener(\n eventName: 'hingeAngleChange',\n listenerFunc: (event: HingeAngleResult) => void,\n ): Promise<PluginListenerHandle>;\n\n /**\n * Listen for size class changes, such as unfolding, rotating, or resizing.\n *\n * @since 8.2.0\n * @param eventName The event name. Must be 'sizeClassChange'.\n * @param listenerFunc Callback invoked with the new size class.\n * @returns {Promise<PluginListenerHandle>} A promise that resolves to a listener handle.\n */\n addListener(\n eventName: 'sizeClassChange',\n listenerFunc: (sizeClass: SizeClass) => void,\n ): Promise<PluginListenerHandle>;\n\n /**\n * Remove all listeners for this plugin.\n *\n * Removes all registered event listeners.\n *\n * @since 1.0.0\n * @returns {Promise<void>} A promise that resolves when all listeners are removed.\n *\n * @example\n * ```typescript\n * await ScreenOrientation.removeAllListeners();\n * ```\n */\n removeAllListeners(): Promise<void>;\n\n /**\n * Get the native plugin version.\n *\n * Returns the current version of the native plugin implementation.\n *\n * @since 1.0.0\n * @returns {Promise<{ version: string }>} A promise that resolves with the version string.\n *\n * @example\n * ```typescript\n * const { version } = await ScreenOrientation.getPluginVersion();\n * console.log('Plugin version:', version);\n * ```\n */\n getPluginVersion(): Promise<{ version: string }>;\n}\n"]}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
const EDGE_TOLERANCE = 1;
|
|
2
|
+
export function splitViewport(fold, width, height) {
|
|
3
|
+
const whole = [{ x: 0, y: 0, width, height }];
|
|
4
|
+
const hinge = fold === null || fold === void 0 ? void 0 : fold.hingeBounds;
|
|
5
|
+
if (!(fold === null || fold === void 0 ? void 0 : fold.isSeparating) || !hinge)
|
|
6
|
+
return whole;
|
|
7
|
+
if (fold.hingeOrientation === 'vertical') {
|
|
8
|
+
const right = hinge.x + hinge.width;
|
|
9
|
+
const spansHeight = hinge.y <= EDGE_TOLERANCE && hinge.y + hinge.height >= height - EDGE_TOLERANCE;
|
|
10
|
+
if (!spansHeight || hinge.x <= 0 || right >= width)
|
|
11
|
+
return whole;
|
|
12
|
+
return [
|
|
13
|
+
{ x: 0, y: 0, width: hinge.x, height },
|
|
14
|
+
{ x: right, y: 0, width: width - right, height },
|
|
15
|
+
];
|
|
16
|
+
}
|
|
17
|
+
const bottom = hinge.y + hinge.height;
|
|
18
|
+
const spansWidth = hinge.x <= EDGE_TOLERANCE && hinge.x + hinge.width >= width - EDGE_TOLERANCE;
|
|
19
|
+
if (!spansWidth || hinge.y <= 0 || bottom >= height)
|
|
20
|
+
return whole;
|
|
21
|
+
return [
|
|
22
|
+
{ x: 0, y: 0, width, height: hinge.y },
|
|
23
|
+
{ x: 0, y: bottom, width, height: height - bottom },
|
|
24
|
+
];
|
|
25
|
+
}
|
|
26
|
+
//# sourceMappingURL=segments.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"segments.js","sourceRoot":"","sources":["../../src/segments.ts"],"names":[],"mappings":"AASA,MAAM,cAAc,GAAG,CAAC,CAAC;AAEzB,MAAM,UAAU,aAAa,CAAC,IAAsB,EAAE,KAAa,EAAE,MAAc;IACjF,MAAM,KAAK,GAAG,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,KAAK,EAAE,MAAM,EAAE,CAAC,CAAC;IAE9C,MAAM,KAAK,GAAG,IAAI,aAAJ,IAAI,uBAAJ,IAAI,CAAE,WAAW,CAAC;IAChC,IAAI,CAAC,CAAA,IAAI,aAAJ,IAAI,uBAAJ,IAAI,CAAE,YAAY,CAAA,IAAI,CAAC,KAAK;QAAE,OAAO,KAAK,CAAC;IAEhD,IAAI,IAAI,CAAC,gBAAgB,KAAK,UAAU,EAAE,CAAC;QACzC,MAAM,KAAK,GAAG,KAAK,CAAC,CAAC,GAAG,KAAK,CAAC,KAAK,CAAC;QACpC,MAAM,WAAW,GAAG,KAAK,CAAC,CAAC,IAAI,cAAc,IAAI,KAAK,CAAC,CAAC,GAAG,KAAK,CAAC,MAAM,IAAI,MAAM,GAAG,cAAc,CAAC;QACnG,IAAI,CAAC,WAAW,IAAI,KAAK,CAAC,CAAC,IAAI,CAAC,IAAI,KAAK,IAAI,KAAK;YAAE,OAAO,KAAK,CAAC;QAEjE,OAAO;YACL,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,KAAK,EAAE,KAAK,CAAC,CAAC,EAAE,MAAM,EAAE;YACtC,EAAE,CAAC,EAAE,KAAK,EAAE,CAAC,EAAE,CAAC,EAAE,KAAK,EAAE,KAAK,GAAG,KAAK,EAAE,MAAM,EAAE;SACjD,CAAC;IACJ,CAAC;IAED,MAAM,MAAM,GAAG,KAAK,CAAC,CAAC,GAAG,KAAK,CAAC,MAAM,CAAC;IACtC,MAAM,UAAU,GAAG,KAAK,CAAC,CAAC,IAAI,cAAc,IAAI,KAAK,CAAC,CAAC,GAAG,KAAK,CAAC,KAAK,IAAI,KAAK,GAAG,cAAc,CAAC;IAChG,IAAI,CAAC,UAAU,IAAI,KAAK,CAAC,CAAC,IAAI,CAAC,IAAI,MAAM,IAAI,MAAM;QAAE,OAAO,KAAK,CAAC;IAElE,OAAO;QACL,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,KAAK,EAAE,MAAM,EAAE,KAAK,CAAC,CAAC,EAAE;QACtC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,GAAG,MAAM,EAAE;KACpD,CAAC;AACJ,CAAC","sourcesContent":["import type { FoldState } from './definitions';\n\nexport interface SegmentRect {\n x: number;\n y: number;\n width: number;\n height: number;\n}\n\nconst EDGE_TOLERANCE = 1;\n\nexport function splitViewport(fold: FoldState | null, width: number, height: number): SegmentRect[] {\n const whole = [{ x: 0, y: 0, width, height }];\n\n const hinge = fold?.hingeBounds;\n if (!fold?.isSeparating || !hinge) return whole;\n\n if (fold.hingeOrientation === 'vertical') {\n const right = hinge.x + hinge.width;\n const spansHeight = hinge.y <= EDGE_TOLERANCE && hinge.y + hinge.height >= height - EDGE_TOLERANCE;\n if (!spansHeight || hinge.x <= 0 || right >= width) return whole;\n\n return [\n { x: 0, y: 0, width: hinge.x, height },\n { x: right, y: 0, width: width - right, height },\n ];\n }\n\n const bottom = hinge.y + hinge.height;\n const spansWidth = hinge.x <= EDGE_TOLERANCE && hinge.x + hinge.width >= width - EDGE_TOLERANCE;\n if (!spansWidth || hinge.y <= 0 || bottom >= height) return whole;\n\n return [\n { x: 0, y: 0, width, height: hinge.y },\n { x: 0, y: bottom, width, height: height - bottom },\n ];\n}\n"]}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
const MEDIUM_WIDTH = 600;
|
|
2
|
+
const EXPANDED_WIDTH = 840;
|
|
3
|
+
const LARGE_WIDTH = 1200;
|
|
4
|
+
const EXTRA_LARGE_WIDTH = 1600;
|
|
5
|
+
const MEDIUM_HEIGHT = 480;
|
|
6
|
+
const EXPANDED_HEIGHT = 900;
|
|
7
|
+
function widthClassOf(width) {
|
|
8
|
+
if (width >= EXTRA_LARGE_WIDTH)
|
|
9
|
+
return 'extraLarge';
|
|
10
|
+
if (width >= LARGE_WIDTH)
|
|
11
|
+
return 'large';
|
|
12
|
+
if (width >= EXPANDED_WIDTH)
|
|
13
|
+
return 'expanded';
|
|
14
|
+
if (width >= MEDIUM_WIDTH)
|
|
15
|
+
return 'medium';
|
|
16
|
+
return 'compact';
|
|
17
|
+
}
|
|
18
|
+
function heightClassOf(height) {
|
|
19
|
+
if (height >= EXPANDED_HEIGHT)
|
|
20
|
+
return 'expanded';
|
|
21
|
+
if (height >= MEDIUM_HEIGHT)
|
|
22
|
+
return 'medium';
|
|
23
|
+
return 'compact';
|
|
24
|
+
}
|
|
25
|
+
export function sizeClassOf(width, height) {
|
|
26
|
+
return {
|
|
27
|
+
horizontal: width >= MEDIUM_WIDTH ? 'regular' : 'compact',
|
|
28
|
+
vertical: height >= MEDIUM_HEIGHT ? 'regular' : 'compact',
|
|
29
|
+
widthClass: widthClassOf(width),
|
|
30
|
+
heightClass: heightClassOf(height),
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
//# sourceMappingURL=size-class.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"size-class.js","sourceRoot":"","sources":["../../src/size-class.ts"],"names":[],"mappings":"AAEA,MAAM,YAAY,GAAG,GAAG,CAAC;AACzB,MAAM,cAAc,GAAG,GAAG,CAAC;AAC3B,MAAM,WAAW,GAAG,IAAI,CAAC;AACzB,MAAM,iBAAiB,GAAG,IAAI,CAAC;AAC/B,MAAM,aAAa,GAAG,GAAG,CAAC;AAC1B,MAAM,eAAe,GAAG,GAAG,CAAC;AAE5B,SAAS,YAAY,CAAC,KAAa;IACjC,IAAI,KAAK,IAAI,iBAAiB;QAAE,OAAO,YAAY,CAAC;IACpD,IAAI,KAAK,IAAI,WAAW;QAAE,OAAO,OAAO,CAAC;IACzC,IAAI,KAAK,IAAI,cAAc;QAAE,OAAO,UAAU,CAAC;IAC/C,IAAI,KAAK,IAAI,YAAY;QAAE,OAAO,QAAQ,CAAC;IAC3C,OAAO,SAAS,CAAC;AACnB,CAAC;AAED,SAAS,aAAa,CAAC,MAAc;IACnC,IAAI,MAAM,IAAI,eAAe;QAAE,OAAO,UAAU,CAAC;IACjD,IAAI,MAAM,IAAI,aAAa;QAAE,OAAO,QAAQ,CAAC;IAC7C,OAAO,SAAS,CAAC;AACnB,CAAC;AAED,MAAM,UAAU,WAAW,CAAC,KAAa,EAAE,MAAc;IACvD,OAAO;QACL,UAAU,EAAE,KAAK,IAAI,YAAY,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,SAAS;QACzD,QAAQ,EAAE,MAAM,IAAI,aAAa,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,SAAS;QACzD,UAAU,EAAE,YAAY,CAAC,KAAK,CAAC;QAC/B,WAAW,EAAE,aAAa,CAAC,MAAM,CAAC;KACnC,CAAC;AACJ,CAAC","sourcesContent":["import type { SizeClass } from './definitions';\n\nconst MEDIUM_WIDTH = 600;\nconst EXPANDED_WIDTH = 840;\nconst LARGE_WIDTH = 1200;\nconst EXTRA_LARGE_WIDTH = 1600;\nconst MEDIUM_HEIGHT = 480;\nconst EXPANDED_HEIGHT = 900;\n\nfunction widthClassOf(width: number): SizeClass['widthClass'] {\n if (width >= EXTRA_LARGE_WIDTH) return 'extraLarge';\n if (width >= LARGE_WIDTH) return 'large';\n if (width >= EXPANDED_WIDTH) return 'expanded';\n if (width >= MEDIUM_WIDTH) return 'medium';\n return 'compact';\n}\n\nfunction heightClassOf(height: number): SizeClass['heightClass'] {\n if (height >= EXPANDED_HEIGHT) return 'expanded';\n if (height >= MEDIUM_HEIGHT) return 'medium';\n return 'compact';\n}\n\nexport function sizeClassOf(width: number, height: number): SizeClass {\n return {\n horizontal: width >= MEDIUM_WIDTH ? 'regular' : 'compact',\n vertical: height >= MEDIUM_HEIGHT ? 'regular' : 'compact',\n widthClass: widthClassOf(width),\n heightClass: heightClassOf(height),\n };\n}\n"]}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import type { DeviceFoldableResult, FoldState } from './definitions';
|
|
2
|
+
type DevicePostureType = 'continuous' | 'folded';
|
|
3
|
+
interface DevicePosture extends EventTarget {
|
|
4
|
+
readonly type: DevicePostureType;
|
|
5
|
+
}
|
|
6
|
+
interface ViewportSegments {
|
|
7
|
+
readonly segments: readonly {
|
|
8
|
+
x: number;
|
|
9
|
+
y: number;
|
|
10
|
+
width: number;
|
|
11
|
+
height: number;
|
|
12
|
+
}[] | null;
|
|
13
|
+
}
|
|
14
|
+
declare global {
|
|
15
|
+
interface Navigator {
|
|
16
|
+
readonly devicePosture?: DevicePosture;
|
|
17
|
+
}
|
|
18
|
+
interface Window {
|
|
19
|
+
readonly viewport?: ViewportSegments;
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
export declare function webFoldApisAvailable(): boolean;
|
|
23
|
+
export declare function webDeviceFoldable(): DeviceFoldableResult;
|
|
24
|
+
export declare function readWebFoldState(width: number, height: number): FoldState;
|
|
25
|
+
export declare function foldStateKey(state: FoldState): string;
|
|
26
|
+
export {};
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
import { splitViewport } from './segments';
|
|
2
|
+
const FLAT_FOLD = { state: 'flat', isSeparating: false, posture: 'flat' };
|
|
3
|
+
export function webFoldApisAvailable() {
|
|
4
|
+
return (typeof window !== 'undefined' &&
|
|
5
|
+
typeof navigator !== 'undefined' &&
|
|
6
|
+
('devicePosture' in navigator || 'viewport' in window));
|
|
7
|
+
}
|
|
8
|
+
export function webDeviceFoldable() {
|
|
9
|
+
if (!webFoldApisAvailable()) {
|
|
10
|
+
return { foldable: false, supportsTabletop: false };
|
|
11
|
+
}
|
|
12
|
+
const fold = readWebFoldState(window.innerWidth, window.innerHeight);
|
|
13
|
+
const foldable = fold.state === 'half-opened' || (fold.isSeparating && fold.hingeBounds != null);
|
|
14
|
+
const supportsTabletop = foldable && (fold.posture === 'tabletop' || fold.hingeOrientation === 'horizontal');
|
|
15
|
+
return { foldable, supportsTabletop };
|
|
16
|
+
}
|
|
17
|
+
export function readWebFoldState(width, height) {
|
|
18
|
+
var _a, _b;
|
|
19
|
+
if (typeof window === 'undefined' || typeof navigator === 'undefined') {
|
|
20
|
+
return FLAT_FOLD;
|
|
21
|
+
}
|
|
22
|
+
const fromSegments = foldFromViewportSegments(width, height);
|
|
23
|
+
if (fromSegments) {
|
|
24
|
+
return fromSegments;
|
|
25
|
+
}
|
|
26
|
+
const postureType = (_b = (_a = navigator.devicePosture) === null || _a === void 0 ? void 0 : _a.type) !== null && _b !== void 0 ? _b : 'continuous';
|
|
27
|
+
if (postureType === 'folded') {
|
|
28
|
+
return { state: 'half-opened', isSeparating: false, posture: 'book' };
|
|
29
|
+
}
|
|
30
|
+
return FLAT_FOLD;
|
|
31
|
+
}
|
|
32
|
+
function foldFromViewportSegments(width, height) {
|
|
33
|
+
var _a;
|
|
34
|
+
const viewport = window.viewport;
|
|
35
|
+
if (!viewport) {
|
|
36
|
+
return null;
|
|
37
|
+
}
|
|
38
|
+
const rawSegments = viewport.segments;
|
|
39
|
+
if (!rawSegments || rawSegments.length !== 2) {
|
|
40
|
+
return null;
|
|
41
|
+
}
|
|
42
|
+
const rects = rawSegments.map((rect) => ({
|
|
43
|
+
x: rect.x,
|
|
44
|
+
y: rect.y,
|
|
45
|
+
width: rect.width,
|
|
46
|
+
height: rect.height,
|
|
47
|
+
}));
|
|
48
|
+
const folded = ((_a = navigator.devicePosture) === null || _a === void 0 ? void 0 : _a.type) === 'folded';
|
|
49
|
+
const state = folded ? 'half-opened' : 'flat';
|
|
50
|
+
const vertical = rects.every((r) => r.y <= 1 && r.height >= height - 1);
|
|
51
|
+
if (vertical) {
|
|
52
|
+
const sorted = [...rects].sort((a, b) => a.x - b.x);
|
|
53
|
+
const left = sorted[0];
|
|
54
|
+
const right = sorted[1];
|
|
55
|
+
const hingeX = left.x + left.width;
|
|
56
|
+
const hingeW = right.x - hingeX;
|
|
57
|
+
if (hingeW < 0) {
|
|
58
|
+
return null;
|
|
59
|
+
}
|
|
60
|
+
const hingeBounds = { x: hingeX, y: 0, width: hingeW, height };
|
|
61
|
+
return finalizeSegmentFold(state, folded, 'vertical', hingeBounds, width, height);
|
|
62
|
+
}
|
|
63
|
+
const horizontal = rects.every((r) => r.x <= 1 && r.width >= width - 1);
|
|
64
|
+
if (horizontal) {
|
|
65
|
+
const sorted = [...rects].sort((a, b) => a.y - b.y);
|
|
66
|
+
const top = sorted[0];
|
|
67
|
+
const bottom = sorted[1];
|
|
68
|
+
const hingeY = top.y + top.height;
|
|
69
|
+
const hingeH = bottom.y - hingeY;
|
|
70
|
+
if (hingeH < 0) {
|
|
71
|
+
return null;
|
|
72
|
+
}
|
|
73
|
+
const hingeBounds = { x: 0, y: hingeY, width, height: hingeH };
|
|
74
|
+
return finalizeSegmentFold(state, folded, 'horizontal', hingeBounds, width, height);
|
|
75
|
+
}
|
|
76
|
+
return null;
|
|
77
|
+
}
|
|
78
|
+
function finalizeSegmentFold(state, folded, hingeOrientation, hingeBounds, width, height) {
|
|
79
|
+
const fold = foldWithHinge(state, folded, hingeOrientation, hingeBounds, true);
|
|
80
|
+
if (splitViewport(fold, width, height).length !== 2) {
|
|
81
|
+
return null;
|
|
82
|
+
}
|
|
83
|
+
return fold;
|
|
84
|
+
}
|
|
85
|
+
function foldWithHinge(state, folded, hingeOrientation, hingeBounds, isSeparating) {
|
|
86
|
+
const posture = !folded ? 'flat' : hingeOrientation === 'horizontal' ? 'tabletop' : 'book';
|
|
87
|
+
const fold = {
|
|
88
|
+
state,
|
|
89
|
+
isSeparating,
|
|
90
|
+
posture,
|
|
91
|
+
hingeOrientation,
|
|
92
|
+
hingeBounds,
|
|
93
|
+
};
|
|
94
|
+
const gap = hingeOrientation === 'vertical' ? hingeBounds.width : hingeBounds.height;
|
|
95
|
+
if (gap > 0) {
|
|
96
|
+
fold.occludedBounds = Object.assign({}, hingeBounds);
|
|
97
|
+
}
|
|
98
|
+
return fold;
|
|
99
|
+
}
|
|
100
|
+
export function foldStateKey(state) {
|
|
101
|
+
return JSON.stringify(state);
|
|
102
|
+
}
|
|
103
|
+
//# sourceMappingURL=web-fold.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"web-fold.js","sourceRoot":"","sources":["../../src/web-fold.ts"],"names":[],"mappings":"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","sourcesContent":["import type { DeviceFoldableResult, FoldBounds, FoldState, HingeOrientation } from './definitions';\nimport { splitViewport, type SegmentRect } from './segments';\n\ntype DevicePostureType = 'continuous' | 'folded';\n\ninterface DevicePosture extends EventTarget {\n readonly type: DevicePostureType;\n}\n\ninterface ViewportSegments {\n readonly segments: readonly { x: number; y: number; width: number; height: number }[] | null;\n}\n\ndeclare global {\n interface Navigator {\n readonly devicePosture?: DevicePosture;\n }\n\n interface Window {\n readonly viewport?: ViewportSegments;\n }\n}\n\nconst FLAT_FOLD: FoldState = { state: 'flat', isSeparating: false, posture: 'flat' };\n\nexport function webFoldApisAvailable(): boolean {\n return (\n typeof window !== 'undefined' &&\n typeof navigator !== 'undefined' &&\n ('devicePosture' in navigator || 'viewport' in window)\n );\n}\n\nexport function webDeviceFoldable(): DeviceFoldableResult {\n if (!webFoldApisAvailable()) {\n return { foldable: false, supportsTabletop: false };\n }\n const fold = readWebFoldState(window.innerWidth, window.innerHeight);\n const foldable = fold.state === 'half-opened' || (fold.isSeparating && fold.hingeBounds != null);\n const supportsTabletop = foldable && (fold.posture === 'tabletop' || fold.hingeOrientation === 'horizontal');\n return { foldable, supportsTabletop };\n}\n\nexport function readWebFoldState(width: number, height: number): FoldState {\n if (typeof window === 'undefined' || typeof navigator === 'undefined') {\n return FLAT_FOLD;\n }\n\n const fromSegments = foldFromViewportSegments(width, height);\n if (fromSegments) {\n return fromSegments;\n }\n\n const postureType = navigator.devicePosture?.type ?? 'continuous';\n if (postureType === 'folded') {\n return { state: 'half-opened', isSeparating: false, posture: 'book' };\n }\n\n return FLAT_FOLD;\n}\n\nfunction foldFromViewportSegments(width: number, height: number): FoldState | null {\n const viewport = window.viewport;\n if (!viewport) {\n return null;\n }\n\n const rawSegments = viewport.segments;\n if (!rawSegments || rawSegments.length !== 2) {\n return null;\n }\n\n const rects: SegmentRect[] = rawSegments.map((rect) => ({\n x: rect.x,\n y: rect.y,\n width: rect.width,\n height: rect.height,\n }));\n\n const folded = navigator.devicePosture?.type === 'folded';\n const state = folded ? 'half-opened' : 'flat';\n\n const vertical = rects.every((r) => r.y <= 1 && r.height >= height - 1);\n if (vertical) {\n const sorted = [...rects].sort((a, b) => a.x - b.x);\n const left = sorted[0];\n const right = sorted[1];\n const hingeX = left.x + left.width;\n const hingeW = right.x - hingeX;\n if (hingeW < 0) {\n return null;\n }\n const hingeBounds: FoldBounds = { x: hingeX, y: 0, width: hingeW, height };\n return finalizeSegmentFold(state, folded, 'vertical', hingeBounds, width, height);\n }\n\n const horizontal = rects.every((r) => r.x <= 1 && r.width >= width - 1);\n if (horizontal) {\n const sorted = [...rects].sort((a, b) => a.y - b.y);\n const top = sorted[0];\n const bottom = sorted[1];\n const hingeY = top.y + top.height;\n const hingeH = bottom.y - hingeY;\n if (hingeH < 0) {\n return null;\n }\n const hingeBounds: FoldBounds = { x: 0, y: hingeY, width, height: hingeH };\n return finalizeSegmentFold(state, folded, 'horizontal', hingeBounds, width, height);\n }\n\n return null;\n}\n\nfunction finalizeSegmentFold(\n state: FoldState['state'],\n folded: boolean,\n hingeOrientation: HingeOrientation,\n hingeBounds: FoldBounds,\n width: number,\n height: number,\n): FoldState | null {\n const fold = foldWithHinge(state, folded, hingeOrientation, hingeBounds, true);\n if (splitViewport(fold, width, height).length !== 2) {\n return null;\n }\n return fold;\n}\n\nfunction foldWithHinge(\n state: FoldState['state'],\n folded: boolean,\n hingeOrientation: HingeOrientation,\n hingeBounds: FoldBounds,\n isSeparating: boolean,\n): FoldState {\n const posture = !folded ? 'flat' : hingeOrientation === 'horizontal' ? 'tabletop' : 'book';\n const fold: FoldState = {\n state,\n isSeparating,\n posture,\n hingeOrientation,\n hingeBounds,\n };\n const gap = hingeOrientation === 'vertical' ? hingeBounds.width : hingeBounds.height;\n if (gap > 0) {\n fold.occludedBounds = { ...hingeBounds };\n }\n return fold;\n}\n\nexport function foldStateKey(state: FoldState): string {\n return JSON.stringify(state);\n}\n"]}
|
package/dist/esm/web.d.ts
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import { WebPlugin } from '@capacitor/core';
|
|
2
2
|
import type { BarPlacement, CapacitorScreenOrientationPlugin, DeviceFoldableResult, FoldState, HingeAngleResult, ReservedRegion, OrientationLockOptions, OrientationType, ScreenOrientationResult, SizeClass, StartOrientationTrackingOptions } from './definitions';
|
|
3
|
-
export
|
|
3
|
+
export { sizeClassOf } from './size-class';
|
|
4
4
|
export declare class CapacitorScreenOrientationWeb extends WebPlugin implements CapacitorScreenOrientationPlugin {
|
|
5
5
|
private readonly pluginVersion;
|
|
6
|
+
private lastFoldKey;
|
|
6
7
|
constructor();
|
|
7
8
|
private lastSizeClass;
|
|
8
9
|
orientation(): Promise<ScreenOrientationResult>;
|
|
@@ -30,5 +31,7 @@ export declare class CapacitorScreenOrientationWeb extends WebPlugin implements
|
|
|
30
31
|
version: string;
|
|
31
32
|
}>;
|
|
32
33
|
private readSizeClass;
|
|
34
|
+
private notifySizeClassIfChanged;
|
|
35
|
+
private notifyFoldIfChanged;
|
|
33
36
|
private mapOrientationType;
|
|
34
37
|
}
|