@symbiote-native/screen-orientation 0.1.0 → 0.3.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 +65 -20
- package/build/angular/index.d.ts +1 -1
- package/build/angular/index.js +1 -1
- package/build/angular/services/screen-orientation.service/index.js +1 -1
- package/build/core/screen-orientation.js +12 -4
- package/build/react/index.d.ts +1 -1
- package/build/react/index.js +1 -1
- package/build/solid/index.d.ts +2 -0
- package/build/solid/index.js +5 -0
- package/build/solid/primitives/create-screen-orientation.d.ts +3 -0
- package/build/solid/primitives/create-screen-orientation.js +38 -0
- package/build/svelte/index.d.ts +2 -0
- package/build/svelte/index.js +5 -0
- package/build/svelte/runes/use-screen-orientation.svelte.d.ts +4 -0
- package/build/svelte/runes/use-screen-orientation.svelte.js +35 -0
- package/build/vue/index.d.ts +1 -1
- package/build/vue/index.js +1 -1
- package/build-ngc/angular/index.d.ts +1 -1
- package/build-ngc/angular/index.js +1 -1
- package/build-ngc/angular/index.js.map +1 -1
- package/build-ngc/angular/services/screen-orientation.service/index.js +4 -4
- package/build-ngc/angular/services/screen-orientation.service/index.js.map +1 -1
- package/build-ngc/core/native-module.js.map +1 -1
- package/build-ngc/core/screen-orientation.js +12 -4
- package/build-ngc/core/screen-orientation.js.map +1 -1
- package/package.json +42 -14
- package/src/angular/index.ts +1 -23
- package/src/angular/services/screen-orientation.service/index.ts +8 -1
- package/src/core/native-module.ts +12 -6
- package/src/core/screen-orientation.ts +52 -14
- package/src/react/hooks/use-screen-orientation/index.ts +7 -5
- package/src/react/index.ts +1 -23
- package/src/solid/index.ts +6 -0
- package/src/solid/primitives/create-screen-orientation.ts +57 -0
- package/src/svelte/index.ts +6 -0
- package/src/svelte/runes/use-screen-orientation.svelte.ts +52 -0
- package/src/svelte/svelte-ambient.d.ts +6 -0
- package/src/vue/index.ts +1 -23
package/README.md
CHANGED
|
@@ -3,7 +3,8 @@
|
|
|
3
3
|
Port of [`expo-screen-orientation`](https://docs.expo.dev/versions/latest/sdk/screen-orientation/)
|
|
4
4
|
for [SymbioteNative](../../README.md) — orientation locking (`lockAsync`/`lockPlatformAsync`/
|
|
5
5
|
`unlockAsync`), reading the current orientation and lock, and an auto-updating orientation-change
|
|
6
|
-
subscription, reachable from every adapter (React, Vue, Angular), not just
|
|
6
|
+
subscription, reachable from every adapter (React, Vue, Svelte, Solid, Angular), not just
|
|
7
|
+
React.
|
|
7
8
|
|
|
8
9
|
Built the same way as [`@symbiote-native/network`](../network) and
|
|
9
10
|
[`@symbiote-native/device`](../device), an `expo-modules-core`-based wrapper (see the
|
|
@@ -31,12 +32,12 @@ into the native host app **once**, covering this package and every other `expo-m
|
|
|
31
32
|
package (`@symbiote-native/network`, `@symbiote-native/device`, `@symbiote-native/sensors`, ...)
|
|
32
33
|
with zero further changes:
|
|
33
34
|
|
|
34
|
-
| Platform | Touches
|
|
35
|
-
|
|
36
|
-
| iOS
|
|
37
|
-
| iOS
|
|
38
|
-
| Android
|
|
39
|
-
| Android
|
|
35
|
+
| Platform | Touches |
|
|
36
|
+
| -------- | --------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
37
|
+
| iOS | `ios/Podfile` — add `use_expo_modules!` |
|
|
38
|
+
| iOS | `AppDelegate.swift` — Expo's runtime-bootstrap hook |
|
|
39
|
+
| Android | `settings.gradle` / `app/build.gradle` — resolve and include the Expo Gradle projects |
|
|
40
|
+
| Android | `MainApplication.kt` — Expo's bootstrap hook, plus a hand-written native-module name map (there's no `expo` meta-package here to auto-generate one) |
|
|
40
41
|
|
|
41
42
|
Full mechanics — the Podfile pieces that normally ship inside the `expo` package, the `expo`
|
|
42
43
|
peer-dependency exclusion list — live in the `symbiote-expo-native-module` skill. Reference
|
|
@@ -55,23 +56,29 @@ src/core/ screen-orientation.ts — lock*/unlock/get* functions +
|
|
|
55
56
|
Orientation/OrientationLock/SizeClassIOS/WebOrientationLock/WebOrientation
|
|
56
57
|
enums, PlatformOrientationInfo, ScreenOrientationInfo,
|
|
57
58
|
OrientationChangeEvent, hand-ported from ScreenOrientation.types.ts, plus
|
|
58
|
-
ScreenOrientationState (
|
|
59
|
+
ScreenOrientationState (the shape every adapter's wrapper returns).
|
|
59
60
|
src/react/hooks/ @symbiote-native/screen-orientation/react — useScreenOrientation
|
|
60
61
|
src/vue/composables/ @symbiote-native/screen-orientation/vue — useScreenOrientation (same name)
|
|
62
|
+
src/svelte/runes/ @symbiote-native/screen-orientation/svelte — useScreenOrientation (same name)
|
|
63
|
+
src/solid/primitives/ @symbiote-native/screen-orientation/solid — createScreenOrientation
|
|
64
|
+
(returns an Accessor; Solid reserves `use*` for consuming existing state)
|
|
61
65
|
src/angular/services/ @symbiote-native/screen-orientation/angular — ScreenOrientationService
|
|
62
66
|
(`.connect()` returns a Signal)
|
|
63
67
|
```
|
|
64
68
|
|
|
65
|
-
Each adapter's hook/composable/service is a thin lifecycle wrapper (seed from
|
|
66
|
-
`getOrientationAsync()`/`getOrientationLockAsync()` calls, subscribe to
|
|
69
|
+
Each adapter's hook/composable/rune/primitive/service is a thin lifecycle wrapper (seed from
|
|
70
|
+
one-shot `getOrientationAsync()`/`getOrientationLockAsync()` calls, subscribe to
|
|
67
71
|
`addOrientationChangeListener`, unsubscribe on unmount) over the same `core` functions — the
|
|
68
|
-
subscription logic is written once and shared by all
|
|
72
|
+
subscription logic is written once and shared by all of them.
|
|
69
73
|
|
|
70
74
|
## Use it
|
|
71
75
|
|
|
72
76
|
```tsx
|
|
73
77
|
// React — examples/expo-react/screens/ScreenOrientationScreen.tsx
|
|
74
|
-
import {
|
|
78
|
+
import {
|
|
79
|
+
lockAsync,
|
|
80
|
+
OrientationLock,
|
|
81
|
+
} from '@symbiote-native/screen-orientation';
|
|
75
82
|
import { useScreenOrientation } from '@symbiote-native/screen-orientation/react';
|
|
76
83
|
|
|
77
84
|
function ScreenOrientationScreen() {
|
|
@@ -81,7 +88,10 @@ function ScreenOrientationScreen() {
|
|
|
81
88
|
<>
|
|
82
89
|
<Text>Orientation: {orientation}</Text>
|
|
83
90
|
<Text>Lock: {orientationLock}</Text>
|
|
84
|
-
<Button
|
|
91
|
+
<Button
|
|
92
|
+
title="Lock landscape"
|
|
93
|
+
onPress={() => lockAsync(OrientationLock.LANDSCAPE)}
|
|
94
|
+
/>
|
|
85
95
|
</>
|
|
86
96
|
);
|
|
87
97
|
}
|
|
@@ -91,7 +101,10 @@ function ScreenOrientationScreen() {
|
|
|
91
101
|
<!-- Vue — examples/expo-vue-sfc/screens/ScreenOrientationScreen.vue -->
|
|
92
102
|
<script setup lang="ts">
|
|
93
103
|
import { Text } from '@symbiote-native/vue';
|
|
94
|
-
import {
|
|
104
|
+
import {
|
|
105
|
+
lockAsync,
|
|
106
|
+
OrientationLock,
|
|
107
|
+
} from '@symbiote-native/screen-orientation';
|
|
95
108
|
import { useScreenOrientation } from '@symbiote-native/screen-orientation/vue';
|
|
96
109
|
|
|
97
110
|
const screenOrientation = useScreenOrientation(); // Ref<ScreenOrientationState>
|
|
@@ -118,6 +131,31 @@ export class ScreenOrientationScreen {
|
|
|
118
131
|
}
|
|
119
132
|
```
|
|
120
133
|
|
|
134
|
+
```tsx
|
|
135
|
+
// Solid — the accessor is CALLED; a Solid component body runs once, so a snapshot would freeze.
|
|
136
|
+
import { Text } from '@symbiote-native/solid';
|
|
137
|
+
import {
|
|
138
|
+
lockAsync,
|
|
139
|
+
OrientationLock,
|
|
140
|
+
} from '@symbiote-native/screen-orientation';
|
|
141
|
+
import { createScreenOrientation } from '@symbiote-native/screen-orientation/solid';
|
|
142
|
+
|
|
143
|
+
function ScreenOrientationScreen() {
|
|
144
|
+
const screenOrientation = createScreenOrientation(); // Accessor<ScreenOrientationState>
|
|
145
|
+
|
|
146
|
+
return (
|
|
147
|
+
<>
|
|
148
|
+
<Text>Orientation: {screenOrientation().orientation}</Text>
|
|
149
|
+
<Text>Lock: {screenOrientation().orientationLock}</Text>
|
|
150
|
+
<Button
|
|
151
|
+
title="Lock landscape"
|
|
152
|
+
onPress={() => lockAsync(OrientationLock.LANDSCAPE)}
|
|
153
|
+
/>
|
|
154
|
+
</>
|
|
155
|
+
);
|
|
156
|
+
}
|
|
157
|
+
```
|
|
158
|
+
|
|
121
159
|
## API
|
|
122
160
|
|
|
123
161
|
A mix of stateless async functions and one listener-based subscription
|
|
@@ -143,19 +181,26 @@ Plus `Orientation` (enum: `UNKNOWN`/`PORTRAIT_UP`/`PORTRAIT_DOWN`/`LANDSCAPE_LEF
|
|
|
143
181
|
`OrientationChangeEvent` — ported from upstream's `ScreenOrientation.types.ts`.
|
|
144
182
|
|
|
145
183
|
```ts
|
|
146
|
-
import {
|
|
184
|
+
import {
|
|
185
|
+
getOrientationAsync,
|
|
186
|
+
addOrientationChangeListener,
|
|
187
|
+
} from '@symbiote-native/screen-orientation';
|
|
147
188
|
|
|
148
189
|
// framework-scoped entry points re-export the same free functions, plus a lifecycle
|
|
149
190
|
// hook/composable/service:
|
|
150
191
|
import { useScreenOrientation } from '@symbiote-native/screen-orientation/react';
|
|
151
192
|
import { useScreenOrientation } from '@symbiote-native/screen-orientation/vue';
|
|
193
|
+
import { useScreenOrientation } from '@symbiote-native/screen-orientation/svelte';
|
|
194
|
+
import { createScreenOrientation } from '@symbiote-native/screen-orientation/solid';
|
|
152
195
|
import { ScreenOrientationService } from '@symbiote-native/screen-orientation/angular';
|
|
153
196
|
```
|
|
154
197
|
|
|
155
|
-
`useScreenOrientation` seeds its initial value
|
|
156
|
-
orientationLock: OrientationLock.UNKNOWN }`) from one-shot
|
|
157
|
-
`getOrientationLockAsync()` calls, then subscribes to
|
|
158
|
-
and unsubscribes on unmount.
|
|
198
|
+
`useScreenOrientation` (Solid: `createScreenOrientation`) seeds its initial value
|
|
199
|
+
(`{ orientation: Orientation.UNKNOWN, orientationLock: OrientationLock.UNKNOWN }`) from one-shot
|
|
200
|
+
`getOrientationAsync()`/`getOrientationLockAsync()` calls, then subscribes to
|
|
201
|
+
`addOrientationChangeListener` for updates, and unsubscribes on unmount. The Solid primitive
|
|
202
|
+
returns an `Accessor<ScreenOrientationState>` and subscribes from its body rather than an effect,
|
|
203
|
+
so nothing can slip between the seed and the subscription.
|
|
159
204
|
|
|
160
205
|
**Note (Android):** `expo-screen-orientation` doesn't emit its own `expoDidUpdateDimensions`
|
|
161
206
|
event on Android — the module piggybacks on RN's own `Dimensions.addEventListener('change', ...)`
|
|
@@ -167,7 +212,7 @@ subscribe to the native `expoDidUpdateDimensions` event directly.
|
|
|
167
212
|
No Fabric/Descriptor angle at all — screen-orientation is a pure async-function + `EventEmitter`
|
|
168
213
|
listener surface, never a view. Tests inject a fake native-module object in place of the real
|
|
169
214
|
`requireNativeModule` resolution (`src/core/screen-orientation.test.ts`,
|
|
170
|
-
`src/{react,vue,angular}/**/*.test.{ts,tsx}`, `vitest`), the same pattern
|
|
215
|
+
`src/{react,vue,svelte,solid,angular}/**/*.test.{ts,tsx}`, `vitest`), the same pattern
|
|
171
216
|
`@symbiote-native/network`/`@symbiote-native/device`/`@symbiote-native/sensors` use — no
|
|
172
217
|
`installFabric()`, no ViewConfig. Native rendering itself is verified on-device — see the parent
|
|
173
218
|
[README](../../README.md).
|
package/build/angular/index.d.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
export { ScreenOrientationService } from './services/screen-orientation.service';
|
|
2
|
-
export
|
|
2
|
+
export * from '../core';
|
package/build/angular/index.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
// ScreenOrientationService is the Angular-only lifecycle half; the free functions and event
|
|
2
2
|
// subscription plumbing all live in core, shared with React/Vue.
|
|
3
3
|
export { ScreenOrientationService } from './services/screen-orientation.service/index.js';
|
|
4
|
-
export
|
|
4
|
+
export * from '../core/index.js';
|
|
@@ -32,7 +32,7 @@ var __runInitializers = (this && this.__runInitializers) || function (thisArg, i
|
|
|
32
32
|
}
|
|
33
33
|
return useValue ? value : void 0;
|
|
34
34
|
};
|
|
35
|
-
import { effect, inject, Injectable, Injector, signal } from '@angular/core';
|
|
35
|
+
import { effect, inject, Injectable, Injector, signal, } from '@angular/core';
|
|
36
36
|
import { addOrientationChangeListener, getOrientationAsync, getOrientationLockAsync, Orientation, OrientationLock, } from '../../../core/index.js';
|
|
37
37
|
// Angular twin of React's `useScreenOrientation` hook and Vue's `useScreenOrientation`
|
|
38
38
|
// composable.
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
// Hand-ported from .vendors/expo/packages/expo-screen-orientation/src/ScreenOrientation.ts
|
|
2
2
|
// (sdk-57). Unlike battery, upstream ScreenOrientation throws UnavailabilityError when the
|
|
3
3
|
// native method is absent — same convention as packages/network/src/core/network.ts.
|
|
4
|
-
import { Platform, UnavailabilityError } from 'expo-modules-core';
|
|
4
|
+
import { Platform, UnavailabilityError, } from 'expo-modules-core';
|
|
5
5
|
import { Dimensions } from 'react-native';
|
|
6
|
-
import { expoScreenOrientation } from './native-module.js';
|
|
6
|
+
import { expoScreenOrientation, } from './native-module.js';
|
|
7
7
|
import { Orientation, OrientationLock, WebOrientationLock, } from './types.js';
|
|
8
8
|
const NATIVE_MODULE_NAME = 'ScreenOrientation';
|
|
9
9
|
let _orientationChangeSubscribers = [];
|
|
@@ -23,13 +23,20 @@ export async function lockAsync(orientationLock) {
|
|
|
23
23
|
await expoScreenOrientation.lockAsync(orientationLock);
|
|
24
24
|
_lastOrientationLock = orientationLock;
|
|
25
25
|
}
|
|
26
|
+
// UPSTREAM-BUG(expo): .vendors/expo/packages/expo-screen-orientation/src/ScreenOrientation.ts:81
|
|
27
|
+
// and :112 - TWO falsy traps, and Android's SCREEN_ORIENTATION_LANDSCAPE is 0: the truthiness
|
|
28
|
+
// check skips the assignment, and even with that one fixed, !platformOrientationParam still
|
|
29
|
+
// rejects the assigned 0. Fixing only the first trap changes nothing.
|
|
30
|
+
// The caller gets a TypeError and the call never reaches native, so landscape cannot be locked
|
|
31
|
+
// on Android through this API.
|
|
32
|
+
// Ported verbatim for parity; do NOT fix without recording a deliberate divergence.
|
|
26
33
|
/** Locks the screen to a platform-specific orientation param — Android constant, iOS
|
|
27
34
|
* orientation array, or web `WebOrientationLock`. */
|
|
28
35
|
export async function lockPlatformAsync(options) {
|
|
29
36
|
if (!expoScreenOrientation.lockPlatformAsync) {
|
|
30
37
|
throw new UnavailabilityError(NATIVE_MODULE_NAME, 'lockPlatformAsync');
|
|
31
38
|
}
|
|
32
|
-
const { screenOrientationConstantAndroid, screenOrientationArrayIOS, screenOrientationLockWeb } = options;
|
|
39
|
+
const { screenOrientationConstantAndroid, screenOrientationArrayIOS, screenOrientationLockWeb, } = options;
|
|
33
40
|
let platformOrientationParam;
|
|
34
41
|
if (Platform.OS === 'android' && screenOrientationConstantAndroid) {
|
|
35
42
|
if (isNaN(screenOrientationConstantAndroid)) {
|
|
@@ -87,7 +94,8 @@ export async function getOrientationLockAsync() {
|
|
|
87
94
|
/** Gets the current orientation lock as a platform-specific value. */
|
|
88
95
|
export async function getPlatformOrientationLockAsync() {
|
|
89
96
|
const platformOrientationLock = await expoScreenOrientation.getPlatformOrientationLockAsync?.();
|
|
90
|
-
if (Platform.OS === 'android' &&
|
|
97
|
+
if (Platform.OS === 'android' &&
|
|
98
|
+
typeof platformOrientationLock === 'number') {
|
|
91
99
|
return { screenOrientationConstantAndroid: platformOrientationLock };
|
|
92
100
|
}
|
|
93
101
|
if (Platform.OS === 'ios' && Array.isArray(platformOrientationLock)) {
|
package/build/react/index.d.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
export { useScreenOrientation } from './hooks/use-screen-orientation';
|
|
2
|
-
export
|
|
2
|
+
export * from '../core';
|
package/build/react/index.js
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
// @symbiote-native/screen-orientation/react: the React entry over the framework-agnostic core.
|
|
2
2
|
export { useScreenOrientation } from './hooks/use-screen-orientation/index.js';
|
|
3
|
-
export
|
|
3
|
+
export * from '../core/index.js';
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
// @symbiote-native/screen-orientation/solid: the Solid entry over the framework-agnostic core —
|
|
2
|
+
// mirrors the lifecycle-bucket naming convention of adapters/solid/src/primitives (never
|
|
3
|
+
// `hooks`/`composables`/`runes`, those are React's, Vue's and Svelte's terms).
|
|
4
|
+
export { createScreenOrientation } from './primitives/create-screen-orientation.js';
|
|
5
|
+
export * from '../core/index.js';
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
// createScreenOrientation — the Solid twin of React's `useScreenOrientation` hook, Vue's
|
|
2
|
+
// composable and Svelte's rune, over the framework-agnostic core (core/screen-orientation.ts).
|
|
3
|
+
// Seeds with one-shot getOrientationAsync()/getOrientationLockAsync() calls before the first
|
|
4
|
+
// native event fires, mirroring packages/network's createNetworkState.
|
|
5
|
+
//
|
|
6
|
+
// `primitives/` and `create*`, never `hooks/`+`use*`: Solid's ecosystem calls a composable
|
|
7
|
+
// reactive function a PRIMITIVE and reserves `use*` for consuming something that already exists.
|
|
8
|
+
// Full rationale in adapters/solid/src/primitives/create-color-scheme.ts.
|
|
9
|
+
//
|
|
10
|
+
// Returns an ACCESSOR, never a snapshot: a Solid component body runs ONCE, so a returned object
|
|
11
|
+
// would pin the caller to the boot orientation.
|
|
12
|
+
//
|
|
13
|
+
// Outside a component or `createRoot` there is no owner for `onCleanup` — Solid warns and the
|
|
14
|
+
// native listener lives for the process. The accessor still tracks; only the teardown is lost.
|
|
15
|
+
import { createSignal, onCleanup } from 'solid-js';
|
|
16
|
+
import { addOrientationChangeListener, getOrientationAsync, getOrientationLockAsync, Orientation, OrientationLock, } from '../../core/index.js';
|
|
17
|
+
export function createScreenOrientation() {
|
|
18
|
+
const [screenOrientation, setScreenOrientation] = createSignal({
|
|
19
|
+
orientation: Orientation.UNKNOWN,
|
|
20
|
+
orientationLock: OrientationLock.UNKNOWN,
|
|
21
|
+
});
|
|
22
|
+
Promise.all([getOrientationAsync(), getOrientationLockAsync()]).then(([orientation, orientationLock]) => {
|
|
23
|
+
setScreenOrientation({ orientation, orientationLock });
|
|
24
|
+
});
|
|
25
|
+
// Subscribed from the primitive body, not from an effect: React/Vue/Svelte start listening a
|
|
26
|
+
// tick after their seed runs, so a rotation landing in that window is lost. Both statements
|
|
27
|
+
// here run in one synchronous tick and nothing can interleave.
|
|
28
|
+
const subscription = addOrientationChangeListener(event => {
|
|
29
|
+
setScreenOrientation({
|
|
30
|
+
orientation: event.orientationInfo.orientation,
|
|
31
|
+
orientationLock: event.orientationLock,
|
|
32
|
+
});
|
|
33
|
+
});
|
|
34
|
+
onCleanup(() => {
|
|
35
|
+
subscription.remove();
|
|
36
|
+
});
|
|
37
|
+
return screenOrientation;
|
|
38
|
+
}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
// @symbiote-native/screen-orientation/svelte: the Svelte entry over the framework-agnostic core —
|
|
2
|
+
// mirrors the lifecycle-bucket naming convention of adapters/svelte/src/runes (never
|
|
3
|
+
// `hooks`/`composables`, those are React's and Vue's terms).
|
|
4
|
+
export { useScreenOrientation } from './runes/use-screen-orientation.svelte';
|
|
5
|
+
export * from '../core/index.js';
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
// Svelte lifecycle wiring over the framework-agnostic core (core/screen-orientation.ts). Seeds the
|
|
2
|
+
// initial value with one-shot getOrientationAsync()/getOrientationLockAsync() calls before the
|
|
3
|
+
// first native event fires, mirroring packages/network's useNetworkState.
|
|
4
|
+
//
|
|
5
|
+
// `.svelte.ts` extension: runes ($state/$effect) only work there outside a `.svelte` component;
|
|
6
|
+
// `runes/` is Svelte's name for the lifecycle bucket (React's `hooks/`, Vue's `composables/`).
|
|
7
|
+
// Returns a boxed getter, not a bare `$state`: Svelte 5 reactivity is lexically scoped to the
|
|
8
|
+
// declaring module and doesn't survive being returned raw from a plain function, so the caller
|
|
9
|
+
// reads `.current` like unwrapping Vue's `Ref` via `.value`.
|
|
10
|
+
import { addOrientationChangeListener, getOrientationAsync, getOrientationLockAsync, Orientation, OrientationLock, } from '../../core/index.js';
|
|
11
|
+
export function useScreenOrientation() {
|
|
12
|
+
let screenOrientation = $state({
|
|
13
|
+
orientation: Orientation.UNKNOWN,
|
|
14
|
+
orientationLock: OrientationLock.UNKNOWN,
|
|
15
|
+
});
|
|
16
|
+
$effect(() => {
|
|
17
|
+
// Write-only touches of `screenOrientation`, so the effect has no dependency on it and runs
|
|
18
|
+
// once per mount - the twin of Vue's onMounted/onUnmounted pair.
|
|
19
|
+
Promise.all([getOrientationAsync(), getOrientationLockAsync()]).then(([orientation, orientationLock]) => {
|
|
20
|
+
screenOrientation = { orientation, orientationLock };
|
|
21
|
+
});
|
|
22
|
+
const subscription = addOrientationChangeListener(event => {
|
|
23
|
+
screenOrientation = {
|
|
24
|
+
orientation: event.orientationInfo.orientation,
|
|
25
|
+
orientationLock: event.orientationLock,
|
|
26
|
+
};
|
|
27
|
+
});
|
|
28
|
+
return () => subscription.remove();
|
|
29
|
+
});
|
|
30
|
+
return {
|
|
31
|
+
get current() {
|
|
32
|
+
return screenOrientation;
|
|
33
|
+
},
|
|
34
|
+
};
|
|
35
|
+
}
|
package/build/vue/index.d.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
export { useScreenOrientation } from './composables/use-screen-orientation';
|
|
2
|
-
export
|
|
2
|
+
export * from '../core';
|
package/build/vue/index.js
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
// @symbiote-native/screen-orientation/vue: the Vue entry over the framework-agnostic core.
|
|
2
2
|
export { useScreenOrientation } from './composables/use-screen-orientation/index.js';
|
|
3
|
-
export
|
|
3
|
+
export * from '../core/index.js';
|
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
export { ScreenOrientationService } from './services/screen-orientation.service';
|
|
2
|
-
export
|
|
2
|
+
export * from '../core';
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
// ScreenOrientationService is the Angular-only lifecycle half; the free functions and event
|
|
2
2
|
// subscription plumbing all live in core, shared with React/Vue.
|
|
3
3
|
export { ScreenOrientationService } from './services/screen-orientation.service';
|
|
4
|
-
export
|
|
4
|
+
export * from '../core';
|
|
5
5
|
//# sourceMappingURL=index.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/angular/index.ts"],"names":[],"mappings":"AAAA,4FAA4F;AAC5F,iEAAiE;AACjE,OAAO,EAAE,wBAAwB,EAAE,MAAM,uCAAuC,CAAC;AACjF,
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/angular/index.ts"],"names":[],"mappings":"AAAA,4FAA4F;AAC5F,iEAAiE;AACjE,OAAO,EAAE,wBAAwB,EAAE,MAAM,uCAAuC,CAAC;AACjF,cAAc,SAAS,CAAC"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { effect, inject, Injectable, Injector, signal } from '@angular/core';
|
|
1
|
+
import { effect, inject, Injectable, Injector, signal, } from '@angular/core';
|
|
2
2
|
import { addOrientationChangeListener, getOrientationAsync, getOrientationLockAsync, Orientation, OrientationLock, } from '../../../core';
|
|
3
3
|
import * as i0 from "@angular/core";
|
|
4
4
|
// Angular twin of React's `useScreenOrientation` hook and Vue's `useScreenOrientation`
|
|
@@ -24,10 +24,10 @@ export class ScreenOrientationService {
|
|
|
24
24
|
}, { injector: this.injector });
|
|
25
25
|
return screenOrientation.asReadonly();
|
|
26
26
|
}
|
|
27
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.
|
|
28
|
-
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "22.0.
|
|
27
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: ScreenOrientationService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
|
|
28
|
+
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: ScreenOrientationService, providedIn: 'root' });
|
|
29
29
|
}
|
|
30
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.
|
|
30
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: ScreenOrientationService, decorators: [{
|
|
31
31
|
type: Injectable,
|
|
32
32
|
args: [{ providedIn: 'root' }]
|
|
33
33
|
}] });
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../src/angular/services/screen-orientation.service/index.ts"],"names":[],"mappings":"AAAA,OAAO,
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../src/angular/services/screen-orientation.service/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,MAAM,EACN,MAAM,EACN,UAAU,EACV,QAAQ,EACR,MAAM,GAEP,MAAM,eAAe,CAAC;AACvB,OAAO,EACL,4BAA4B,EAC5B,mBAAmB,EACnB,uBAAuB,EACvB,WAAW,EACX,eAAe,GAEhB,MAAM,eAAe,CAAC;;AAEvB,uFAAuF;AACvF,cAAc;AACd,EAAE;AACF,6EAA6E;AAC7E,uDAAuD;AAEvD,MAAM,OAAO,wBAAwB;IAClB,QAAQ,GAAG,MAAM,CAAC,QAAQ,CAAC,CAAC;IAE7C,OAAO;QACL,MAAM,iBAAiB,GAAG,MAAM,CAAyB;YACvD,WAAW,EAAE,WAAW,CAAC,OAAO;YAChC,eAAe,EAAE,eAAe,CAAC,OAAO;SACzC;8FAAC,CAAC;QAEH,MAAM,CACJ,SAAS,CAAC,EAAE;YACV,OAAO,CAAC,GAAG,CAAC,CAAC,mBAAmB,EAAE,EAAE,uBAAuB,EAAE,CAAC,CAAC,CAAC,IAAI,CAClE,CAAC,CAAC,WAAW,EAAE,eAAe,CAAC,EAAE,EAAE,CACjC,iBAAiB,CAAC,GAAG,CAAC,EAAE,WAAW,EAAE,eAAe,EAAE,CAAC,CAC1D,CAAC;YACF,MAAM,YAAY,GAAG,4BAA4B,CAAC,KAAK,CAAC,EAAE,CACxD,iBAAiB,CAAC,GAAG,CAAC;gBACpB,WAAW,EAAE,KAAK,CAAC,eAAe,CAAC,WAAW;gBAC9C,eAAe,EAAE,KAAK,CAAC,eAAe;aACvC,CAAC,CACH,CAAC;YACF,SAAS,CAAC,GAAG,EAAE,CAAC,YAAY,CAAC,MAAM,EAAE,CAAC,CAAC;QACzC,CAAC,EACD,EAAE,QAAQ,EAAE,IAAI,CAAC,QAAQ,EAAE,CAC5B,CAAC;QAEF,OAAO,iBAAiB,CAAC,UAAU,EAAE,CAAC;IACxC,CAAC;uGA3BU,wBAAwB;2GAAxB,wBAAwB,cADX,MAAM;;2FACnB,wBAAwB;kBADpC,UAAU;mBAAC,EAAE,UAAU,EAAE,MAAM,EAAE"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"native-module.js","sourceRoot":"","sources":["../../src/core/native-module.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,mBAAmB,EAAE,MAAM,mBAAmB,CAAC;AASxD,MAAM,mCAAmC,GAAG,uBAAuB,CAAC;
|
|
1
|
+
{"version":3,"file":"native-module.js","sourceRoot":"","sources":["../../src/core/native-module.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,mBAAmB,EAAE,MAAM,mBAAmB,CAAC;AASxD,MAAM,mCAAmC,GAAG,uBAAuB,CAAC;AA6BpE,MAAM,CAAC,MAAM,qBAAqB,GAChC,mBAAmB,CACjB,mCAAmC,CACpC,CAAC"}
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
// Hand-ported from .vendors/expo/packages/expo-screen-orientation/src/ScreenOrientation.ts
|
|
2
2
|
// (sdk-57). Unlike battery, upstream ScreenOrientation throws UnavailabilityError when the
|
|
3
3
|
// native method is absent — same convention as packages/network/src/core/network.ts.
|
|
4
|
-
import { Platform, UnavailabilityError } from 'expo-modules-core';
|
|
4
|
+
import { Platform, UnavailabilityError, } from 'expo-modules-core';
|
|
5
5
|
import { Dimensions } from 'react-native';
|
|
6
|
-
import { expoScreenOrientation } from './native-module';
|
|
6
|
+
import { expoScreenOrientation, } from './native-module';
|
|
7
7
|
import { Orientation, OrientationLock, WebOrientationLock, } from './types';
|
|
8
8
|
const NATIVE_MODULE_NAME = 'ScreenOrientation';
|
|
9
9
|
let _orientationChangeSubscribers = [];
|
|
@@ -23,13 +23,20 @@ export async function lockAsync(orientationLock) {
|
|
|
23
23
|
await expoScreenOrientation.lockAsync(orientationLock);
|
|
24
24
|
_lastOrientationLock = orientationLock;
|
|
25
25
|
}
|
|
26
|
+
// UPSTREAM-BUG(expo): .vendors/expo/packages/expo-screen-orientation/src/ScreenOrientation.ts:81
|
|
27
|
+
// and :112 - TWO falsy traps, and Android's SCREEN_ORIENTATION_LANDSCAPE is 0: the truthiness
|
|
28
|
+
// check skips the assignment, and even with that one fixed, !platformOrientationParam still
|
|
29
|
+
// rejects the assigned 0. Fixing only the first trap changes nothing.
|
|
30
|
+
// The caller gets a TypeError and the call never reaches native, so landscape cannot be locked
|
|
31
|
+
// on Android through this API.
|
|
32
|
+
// Ported verbatim for parity; do NOT fix without recording a deliberate divergence.
|
|
26
33
|
/** Locks the screen to a platform-specific orientation param — Android constant, iOS
|
|
27
34
|
* orientation array, or web `WebOrientationLock`. */
|
|
28
35
|
export async function lockPlatformAsync(options) {
|
|
29
36
|
if (!expoScreenOrientation.lockPlatformAsync) {
|
|
30
37
|
throw new UnavailabilityError(NATIVE_MODULE_NAME, 'lockPlatformAsync');
|
|
31
38
|
}
|
|
32
|
-
const { screenOrientationConstantAndroid, screenOrientationArrayIOS, screenOrientationLockWeb } = options;
|
|
39
|
+
const { screenOrientationConstantAndroid, screenOrientationArrayIOS, screenOrientationLockWeb, } = options;
|
|
33
40
|
let platformOrientationParam;
|
|
34
41
|
if (Platform.OS === 'android' && screenOrientationConstantAndroid) {
|
|
35
42
|
if (isNaN(screenOrientationConstantAndroid)) {
|
|
@@ -87,7 +94,8 @@ export async function getOrientationLockAsync() {
|
|
|
87
94
|
/** Gets the current orientation lock as a platform-specific value. */
|
|
88
95
|
export async function getPlatformOrientationLockAsync() {
|
|
89
96
|
const platformOrientationLock = await expoScreenOrientation.getPlatformOrientationLockAsync?.();
|
|
90
|
-
if (Platform.OS === 'android' &&
|
|
97
|
+
if (Platform.OS === 'android' &&
|
|
98
|
+
typeof platformOrientationLock === 'number') {
|
|
91
99
|
return { screenOrientationConstantAndroid: platformOrientationLock };
|
|
92
100
|
}
|
|
93
101
|
if (Platform.OS === 'ios' && Array.isArray(platformOrientationLock)) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"screen-orientation.js","sourceRoot":"","sources":["../../src/core/screen-orientation.ts"],"names":[],"mappings":"AAAA,2FAA2F;AAC3F,2FAA2F;AAC3F,qFAAqF;AACrF,OAAO,
|
|
1
|
+
{"version":3,"file":"screen-orientation.js","sourceRoot":"","sources":["../../src/core/screen-orientation.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@symbiote-native/screen-orientation",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"description": "expo-screen-orientation wrapped for SymbioteNative — one framework-agnostic core, built once and reachable from the React, Vue, and Angular adapters. Orientation locking (lockAsync/lockPlatformAsync/unlockAsync), the current orientation and lock, and an auto-updating orientation-change hook/composable/service.",
|
|
3
|
+
"version": "0.3.0",
|
|
4
|
+
"description": "expo-screen-orientation wrapped for SymbioteNative — one framework-agnostic core, built once and reachable from the React, Vue, Svelte, Solid, and Angular adapters. Orientation locking (lockAsync/lockPlatformAsync/unlockAsync), the current orientation and lock, and an auto-updating orientation-change hook/composable/service.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": {
|
|
7
7
|
"type": "git",
|
|
@@ -30,6 +30,14 @@
|
|
|
30
30
|
"types": "./build/react/index.d.ts",
|
|
31
31
|
"default": "./build/react/index.js"
|
|
32
32
|
},
|
|
33
|
+
"./svelte": {
|
|
34
|
+
"types": "./build/svelte/index.d.ts",
|
|
35
|
+
"default": "./build/svelte/index.js"
|
|
36
|
+
},
|
|
37
|
+
"./solid": {
|
|
38
|
+
"types": "./build/solid/index.d.ts",
|
|
39
|
+
"default": "./build/solid/index.js"
|
|
40
|
+
},
|
|
33
41
|
"./angular": {
|
|
34
42
|
"types": "./build-ngc/angular/index.d.ts",
|
|
35
43
|
"react-native": "./build-ngc/angular/index.js",
|
|
@@ -53,15 +61,19 @@
|
|
|
53
61
|
"expo-modules-core": "57.0.5"
|
|
54
62
|
},
|
|
55
63
|
"peerDependencies": {
|
|
64
|
+
"@symbiote-native/angular": ">=0.6.2",
|
|
56
65
|
"@symbiote-native/engine": ">=0.1.7",
|
|
66
|
+
"@symbiote-native/react": ">=0.2.8",
|
|
67
|
+
"@symbiote-native/solid": ">=0.0.1",
|
|
68
|
+
"@symbiote-native/svelte": ">=0.1.0",
|
|
69
|
+
"@symbiote-native/vue": ">=0.3.8",
|
|
57
70
|
"@angular/core": ">=20",
|
|
58
71
|
"@vue/runtime-core": "^3.5.13",
|
|
59
72
|
"react": ">=19.0.0",
|
|
60
73
|
"react-native": ">=0.86",
|
|
61
|
-
"
|
|
62
|
-
"
|
|
63
|
-
"
|
|
64
|
-
"@symbiote-native/vue": "0.3.8"
|
|
74
|
+
"solid-js": ">=1.9.0",
|
|
75
|
+
"svelte": ">=5.56.0",
|
|
76
|
+
"vue": ">=3.5.0"
|
|
65
77
|
},
|
|
66
78
|
"peerDependenciesMeta": {
|
|
67
79
|
"@symbiote-native/angular": {
|
|
@@ -70,6 +82,12 @@
|
|
|
70
82
|
"@symbiote-native/react": {
|
|
71
83
|
"optional": true
|
|
72
84
|
},
|
|
85
|
+
"@symbiote-native/solid": {
|
|
86
|
+
"optional": true
|
|
87
|
+
},
|
|
88
|
+
"@symbiote-native/svelte": {
|
|
89
|
+
"optional": true
|
|
90
|
+
},
|
|
73
91
|
"@symbiote-native/vue": {
|
|
74
92
|
"optional": true
|
|
75
93
|
},
|
|
@@ -82,24 +100,34 @@
|
|
|
82
100
|
"react": {
|
|
83
101
|
"optional": true
|
|
84
102
|
},
|
|
103
|
+
"solid-js": {
|
|
104
|
+
"optional": true
|
|
105
|
+
},
|
|
106
|
+
"svelte": {
|
|
107
|
+
"optional": true
|
|
108
|
+
},
|
|
85
109
|
"vue": {
|
|
86
110
|
"optional": true
|
|
87
111
|
}
|
|
88
112
|
},
|
|
89
113
|
"devDependencies": {
|
|
90
|
-
"@angular/compiler": "
|
|
91
|
-
"@angular/compiler-cli": "
|
|
92
|
-
"@angular/core": "
|
|
114
|
+
"@angular/compiler": "~22.0.8",
|
|
115
|
+
"@angular/compiler-cli": "~22.0.8",
|
|
116
|
+
"@angular/core": "~22.0.8",
|
|
93
117
|
"@types/node": "^26.0.0",
|
|
94
118
|
"@types/react": "^19.2.0",
|
|
95
119
|
"@vue/runtime-core": "^3.5.13",
|
|
96
120
|
"react": "19.2.3",
|
|
121
|
+
"solid-js": "^1.9.14",
|
|
122
|
+
"svelte": "^5.56.0",
|
|
97
123
|
"typescript": "~6.0.0",
|
|
98
|
-
"@symbiote-native/angular": "0.
|
|
99
|
-
"@symbiote-native/engine": "0.
|
|
100
|
-
"@symbiote-native/react": "0.
|
|
101
|
-
"@symbiote-native/
|
|
102
|
-
"@symbiote-native/
|
|
124
|
+
"@symbiote-native/angular": "0.8.0",
|
|
125
|
+
"@symbiote-native/engine": "0.3.0",
|
|
126
|
+
"@symbiote-native/react": "0.4.0",
|
|
127
|
+
"@symbiote-native/solid": "0.1.0",
|
|
128
|
+
"@symbiote-native/svelte": "0.3.0",
|
|
129
|
+
"@symbiote-native/test-utils": "0.2.0",
|
|
130
|
+
"@symbiote-native/vue": "0.5.0"
|
|
103
131
|
},
|
|
104
132
|
"scripts": {
|
|
105
133
|
"typecheck": "tsc --build",
|
package/src/angular/index.ts
CHANGED
|
@@ -1,26 +1,4 @@
|
|
|
1
1
|
// ScreenOrientationService is the Angular-only lifecycle half; the free functions and event
|
|
2
2
|
// subscription plumbing all live in core, shared with React/Vue.
|
|
3
3
|
export { ScreenOrientationService } from './services/screen-orientation.service';
|
|
4
|
-
export
|
|
5
|
-
lockAsync,
|
|
6
|
-
lockPlatformAsync,
|
|
7
|
-
unlockAsync,
|
|
8
|
-
getOrientationAsync,
|
|
9
|
-
getOrientationLockAsync,
|
|
10
|
-
getPlatformOrientationLockAsync,
|
|
11
|
-
supportsOrientationLockAsync,
|
|
12
|
-
addOrientationChangeListener,
|
|
13
|
-
removeOrientationChangeListeners,
|
|
14
|
-
removeOrientationChangeListener,
|
|
15
|
-
Orientation,
|
|
16
|
-
OrientationLock,
|
|
17
|
-
SizeClassIOS,
|
|
18
|
-
WebOrientationLock,
|
|
19
|
-
WebOrientation,
|
|
20
|
-
type PlatformOrientationInfo,
|
|
21
|
-
type ScreenOrientationInfo,
|
|
22
|
-
type OrientationChangeEvent,
|
|
23
|
-
type OrientationChangeListener,
|
|
24
|
-
type ScreenOrientationState,
|
|
25
|
-
type EventSubscription,
|
|
26
|
-
} from '../core';
|
|
4
|
+
export * from '../core';
|
|
@@ -1,4 +1,11 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import {
|
|
2
|
+
effect,
|
|
3
|
+
inject,
|
|
4
|
+
Injectable,
|
|
5
|
+
Injector,
|
|
6
|
+
signal,
|
|
7
|
+
type Signal,
|
|
8
|
+
} from '@angular/core';
|
|
2
9
|
import {
|
|
3
10
|
addOrientationChangeListener,
|
|
4
11
|
getOrientationAsync,
|
|
@@ -12,7 +12,8 @@ const EXPO_SCREEN_ORIENTATION_MODULE_NAME = 'ExpoScreenOrientation';
|
|
|
12
12
|
// The platform-specific lock param/return shape is a genuine per-platform union (Android sends/
|
|
13
13
|
// returns a numeric constant, iOS an Orientation[], web a WebOrientationLock string) — never `any`,
|
|
14
14
|
// so screen-orientation.ts can narrow it with typeof/Array.isArray instead of casting.
|
|
15
|
-
export type IPlatformOrientationParam =
|
|
15
|
+
export type IPlatformOrientationParam =
|
|
16
|
+
number | Orientation[] | WebOrientationLock;
|
|
16
17
|
|
|
17
18
|
// Every method is optional for the same reason every sibling package's native module type is
|
|
18
19
|
// (network, device, battery) — each call site in screen-orientation.ts checks for the method's
|
|
@@ -20,17 +21,22 @@ export type IPlatformOrientationParam = number | Orientation[] | WebOrientationL
|
|
|
20
21
|
// capability checks rather than assuming the native module implements the whole surface.
|
|
21
22
|
export type INativeScreenOrientationModule = {
|
|
22
23
|
lockAsync?(orientationLock: OrientationLock): Promise<void>;
|
|
23
|
-
lockPlatformAsync?(
|
|
24
|
+
lockPlatformAsync?(
|
|
25
|
+
platformOrientationParam: IPlatformOrientationParam,
|
|
26
|
+
): Promise<void>;
|
|
24
27
|
getOrientationAsync?(): Promise<Orientation>;
|
|
25
28
|
getOrientationLockAsync?(): Promise<OrientationLock>;
|
|
26
29
|
getPlatformOrientationLockAsync?(): Promise<IPlatformOrientationParam>;
|
|
27
|
-
supportsOrientationLockAsync?(
|
|
30
|
+
supportsOrientationLockAsync?(
|
|
31
|
+
orientationLock: OrientationLock,
|
|
32
|
+
): Promise<boolean>;
|
|
28
33
|
addListener(
|
|
29
34
|
eventName: 'expoDidUpdateDimensions',
|
|
30
35
|
listener: (event: OrientationChangeEvent) => void,
|
|
31
36
|
): EventSubscription;
|
|
32
37
|
};
|
|
33
38
|
|
|
34
|
-
export const expoScreenOrientation =
|
|
35
|
-
|
|
36
|
-
|
|
39
|
+
export const expoScreenOrientation =
|
|
40
|
+
requireNativeModule<INativeScreenOrientationModule>(
|
|
41
|
+
EXPO_SCREEN_ORIENTATION_MODULE_NAME,
|
|
42
|
+
);
|
|
@@ -1,9 +1,16 @@
|
|
|
1
1
|
// Hand-ported from .vendors/expo/packages/expo-screen-orientation/src/ScreenOrientation.ts
|
|
2
2
|
// (sdk-57). Unlike battery, upstream ScreenOrientation throws UnavailabilityError when the
|
|
3
3
|
// native method is absent — same convention as packages/network/src/core/network.ts.
|
|
4
|
-
import {
|
|
4
|
+
import {
|
|
5
|
+
Platform,
|
|
6
|
+
UnavailabilityError,
|
|
7
|
+
type EventSubscription,
|
|
8
|
+
} from 'expo-modules-core';
|
|
5
9
|
import { Dimensions } from 'react-native';
|
|
6
|
-
import {
|
|
10
|
+
import {
|
|
11
|
+
expoScreenOrientation,
|
|
12
|
+
type IPlatformOrientationParam,
|
|
13
|
+
} from './native-module';
|
|
7
14
|
import {
|
|
8
15
|
Orientation,
|
|
9
16
|
OrientationLock,
|
|
@@ -19,7 +26,9 @@ let _orientationChangeSubscribers: EventSubscription[] = [];
|
|
|
19
26
|
let _lastOrientationLock: OrientationLock = OrientationLock.UNKNOWN;
|
|
20
27
|
|
|
21
28
|
/** Locks the screen to the given orientation. */
|
|
22
|
-
export async function lockAsync(
|
|
29
|
+
export async function lockAsync(
|
|
30
|
+
orientationLock: OrientationLock,
|
|
31
|
+
): Promise<void> {
|
|
23
32
|
if (!expoScreenOrientation.lockAsync) {
|
|
24
33
|
throw new UnavailabilityError(NATIVE_MODULE_NAME, 'lockAsync');
|
|
25
34
|
}
|
|
@@ -34,14 +43,26 @@ export async function lockAsync(orientationLock: OrientationLock): Promise<void>
|
|
|
34
43
|
_lastOrientationLock = orientationLock;
|
|
35
44
|
}
|
|
36
45
|
|
|
46
|
+
// UPSTREAM-BUG(expo): .vendors/expo/packages/expo-screen-orientation/src/ScreenOrientation.ts:81
|
|
47
|
+
// and :112 - TWO falsy traps, and Android's SCREEN_ORIENTATION_LANDSCAPE is 0: the truthiness
|
|
48
|
+
// check skips the assignment, and even with that one fixed, !platformOrientationParam still
|
|
49
|
+
// rejects the assigned 0. Fixing only the first trap changes nothing.
|
|
50
|
+
// The caller gets a TypeError and the call never reaches native, so landscape cannot be locked
|
|
51
|
+
// on Android through this API.
|
|
52
|
+
// Ported verbatim for parity; do NOT fix without recording a deliberate divergence.
|
|
37
53
|
/** Locks the screen to a platform-specific orientation param — Android constant, iOS
|
|
38
54
|
* orientation array, or web `WebOrientationLock`. */
|
|
39
|
-
export async function lockPlatformAsync(
|
|
55
|
+
export async function lockPlatformAsync(
|
|
56
|
+
options: PlatformOrientationInfo,
|
|
57
|
+
): Promise<void> {
|
|
40
58
|
if (!expoScreenOrientation.lockPlatformAsync) {
|
|
41
59
|
throw new UnavailabilityError(NATIVE_MODULE_NAME, 'lockPlatformAsync');
|
|
42
60
|
}
|
|
43
|
-
const {
|
|
44
|
-
|
|
61
|
+
const {
|
|
62
|
+
screenOrientationConstantAndroid,
|
|
63
|
+
screenOrientationArrayIOS,
|
|
64
|
+
screenOrientationLockWeb,
|
|
65
|
+
} = options;
|
|
45
66
|
let platformOrientationParam: IPlatformOrientationParam | undefined;
|
|
46
67
|
if (Platform.OS === 'android' && screenOrientationConstantAndroid) {
|
|
47
68
|
if (isNaN(screenOrientationConstantAndroid)) {
|
|
@@ -68,12 +89,16 @@ export async function lockPlatformAsync(options: PlatformOrientationInfo): Promi
|
|
|
68
89
|
} else if (Platform.OS === 'web' && screenOrientationLockWeb) {
|
|
69
90
|
const webOrientationLocks = Object.values(WebOrientationLock);
|
|
70
91
|
if (!webOrientationLocks.includes(screenOrientationLockWeb)) {
|
|
71
|
-
throw new TypeError(
|
|
92
|
+
throw new TypeError(
|
|
93
|
+
`Invalid Web Orientation Lock: ${screenOrientationLockWeb}`,
|
|
94
|
+
);
|
|
72
95
|
}
|
|
73
96
|
platformOrientationParam = screenOrientationLockWeb;
|
|
74
97
|
}
|
|
75
98
|
if (!platformOrientationParam) {
|
|
76
|
-
throw new TypeError(
|
|
99
|
+
throw new TypeError(
|
|
100
|
+
'lockPlatformAsync cannot be called with undefined option properties',
|
|
101
|
+
);
|
|
77
102
|
}
|
|
78
103
|
await expoScreenOrientation.lockPlatformAsync(platformOrientationParam);
|
|
79
104
|
_lastOrientationLock = OrientationLock.OTHER;
|
|
@@ -106,8 +131,12 @@ export async function getOrientationLockAsync(): Promise<OrientationLock> {
|
|
|
106
131
|
|
|
107
132
|
/** Gets the current orientation lock as a platform-specific value. */
|
|
108
133
|
export async function getPlatformOrientationLockAsync(): Promise<PlatformOrientationInfo> {
|
|
109
|
-
const platformOrientationLock =
|
|
110
|
-
|
|
134
|
+
const platformOrientationLock =
|
|
135
|
+
await expoScreenOrientation.getPlatformOrientationLockAsync?.();
|
|
136
|
+
if (
|
|
137
|
+
Platform.OS === 'android' &&
|
|
138
|
+
typeof platformOrientationLock === 'number'
|
|
139
|
+
) {
|
|
111
140
|
return { screenOrientationConstantAndroid: platformOrientationLock };
|
|
112
141
|
}
|
|
113
142
|
if (Platform.OS === 'ios' && Array.isArray(platformOrientationLock)) {
|
|
@@ -124,7 +153,10 @@ export async function supportsOrientationLockAsync(
|
|
|
124
153
|
orientationLock: OrientationLock,
|
|
125
154
|
): Promise<boolean> {
|
|
126
155
|
if (!expoScreenOrientation.supportsOrientationLockAsync) {
|
|
127
|
-
throw new UnavailabilityError(
|
|
156
|
+
throw new UnavailabilityError(
|
|
157
|
+
NATIVE_MODULE_NAME,
|
|
158
|
+
'supportsOrientationLockAsync',
|
|
159
|
+
);
|
|
128
160
|
}
|
|
129
161
|
const orientationLocks = Object.values(OrientationLock);
|
|
130
162
|
if (!orientationLocks.includes(orientationLock)) {
|
|
@@ -138,7 +170,9 @@ export function addOrientationChangeListener(
|
|
|
138
170
|
listener: OrientationChangeListener,
|
|
139
171
|
): EventSubscription {
|
|
140
172
|
if (typeof listener !== 'function') {
|
|
141
|
-
throw new TypeError(
|
|
173
|
+
throw new TypeError(
|
|
174
|
+
`addOrientationChangeListener cannot be called with ${listener}`,
|
|
175
|
+
);
|
|
142
176
|
}
|
|
143
177
|
const subscription = createDidUpdateDimensionsSubscription(listener);
|
|
144
178
|
_orientationChangeSubscribers.push(subscription);
|
|
@@ -155,12 +189,16 @@ export function removeOrientationChangeListeners(): void {
|
|
|
155
189
|
}
|
|
156
190
|
|
|
157
191
|
/** Removes a single orientation-change listener's subscription. */
|
|
158
|
-
export function removeOrientationChangeListener(
|
|
192
|
+
export function removeOrientationChangeListener(
|
|
193
|
+
subscription: EventSubscription,
|
|
194
|
+
): void {
|
|
159
195
|
if (!subscription || !subscription.remove) {
|
|
160
196
|
throw new TypeError('Must pass in a valid subscription');
|
|
161
197
|
}
|
|
162
198
|
subscription.remove();
|
|
163
|
-
_orientationChangeSubscribers = _orientationChangeSubscribers.filter(
|
|
199
|
+
_orientationChangeSubscribers = _orientationChangeSubscribers.filter(
|
|
200
|
+
sub => sub !== subscription,
|
|
201
|
+
);
|
|
164
202
|
}
|
|
165
203
|
|
|
166
204
|
// IMPORTANT: Android doesn't emit `expoDidUpdateDimensions` — RN's own Dimensions module does,
|
|
@@ -12,14 +12,16 @@ import {
|
|
|
12
12
|
} from '../../../core';
|
|
13
13
|
|
|
14
14
|
export function useScreenOrientation(): ScreenOrientationState {
|
|
15
|
-
const [screenOrientation, setScreenOrientation] =
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
15
|
+
const [screenOrientation, setScreenOrientation] =
|
|
16
|
+
useState<ScreenOrientationState>({
|
|
17
|
+
orientation: Orientation.UNKNOWN,
|
|
18
|
+
orientationLock: OrientationLock.UNKNOWN,
|
|
19
|
+
});
|
|
19
20
|
|
|
20
21
|
useEffect(() => {
|
|
21
22
|
Promise.all([getOrientationAsync(), getOrientationLockAsync()]).then(
|
|
22
|
-
([orientation, orientationLock]) =>
|
|
23
|
+
([orientation, orientationLock]) =>
|
|
24
|
+
setScreenOrientation({ orientation, orientationLock }),
|
|
23
25
|
);
|
|
24
26
|
const subscription = addOrientationChangeListener(event =>
|
|
25
27
|
setScreenOrientation({
|
package/src/react/index.ts
CHANGED
|
@@ -1,26 +1,4 @@
|
|
|
1
1
|
// @symbiote-native/screen-orientation/react: the React entry over the framework-agnostic core.
|
|
2
2
|
|
|
3
3
|
export { useScreenOrientation } from './hooks/use-screen-orientation';
|
|
4
|
-
export
|
|
5
|
-
lockAsync,
|
|
6
|
-
lockPlatformAsync,
|
|
7
|
-
unlockAsync,
|
|
8
|
-
getOrientationAsync,
|
|
9
|
-
getOrientationLockAsync,
|
|
10
|
-
getPlatformOrientationLockAsync,
|
|
11
|
-
supportsOrientationLockAsync,
|
|
12
|
-
addOrientationChangeListener,
|
|
13
|
-
removeOrientationChangeListeners,
|
|
14
|
-
removeOrientationChangeListener,
|
|
15
|
-
Orientation,
|
|
16
|
-
OrientationLock,
|
|
17
|
-
SizeClassIOS,
|
|
18
|
-
WebOrientationLock,
|
|
19
|
-
WebOrientation,
|
|
20
|
-
type PlatformOrientationInfo,
|
|
21
|
-
type ScreenOrientationInfo,
|
|
22
|
-
type OrientationChangeEvent,
|
|
23
|
-
type OrientationChangeListener,
|
|
24
|
-
type ScreenOrientationState,
|
|
25
|
-
type EventSubscription,
|
|
26
|
-
} from '../core';
|
|
4
|
+
export * from '../core';
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
// @symbiote-native/screen-orientation/solid: the Solid entry over the framework-agnostic core —
|
|
2
|
+
// mirrors the lifecycle-bucket naming convention of adapters/solid/src/primitives (never
|
|
3
|
+
// `hooks`/`composables`/`runes`, those are React's, Vue's and Svelte's terms).
|
|
4
|
+
|
|
5
|
+
export { createScreenOrientation } from './primitives/create-screen-orientation';
|
|
6
|
+
export * from '../core';
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
// createScreenOrientation — the Solid twin of React's `useScreenOrientation` hook, Vue's
|
|
2
|
+
// composable and Svelte's rune, over the framework-agnostic core (core/screen-orientation.ts).
|
|
3
|
+
// Seeds with one-shot getOrientationAsync()/getOrientationLockAsync() calls before the first
|
|
4
|
+
// native event fires, mirroring packages/network's createNetworkState.
|
|
5
|
+
//
|
|
6
|
+
// `primitives/` and `create*`, never `hooks/`+`use*`: Solid's ecosystem calls a composable
|
|
7
|
+
// reactive function a PRIMITIVE and reserves `use*` for consuming something that already exists.
|
|
8
|
+
// Full rationale in adapters/solid/src/primitives/create-color-scheme.ts.
|
|
9
|
+
//
|
|
10
|
+
// Returns an ACCESSOR, never a snapshot: a Solid component body runs ONCE, so a returned object
|
|
11
|
+
// would pin the caller to the boot orientation.
|
|
12
|
+
//
|
|
13
|
+
// Outside a component or `createRoot` there is no owner for `onCleanup` — Solid warns and the
|
|
14
|
+
// native listener lives for the process. The accessor still tracks; only the teardown is lost.
|
|
15
|
+
|
|
16
|
+
import { createSignal, onCleanup, type Accessor } from 'solid-js';
|
|
17
|
+
import {
|
|
18
|
+
addOrientationChangeListener,
|
|
19
|
+
getOrientationAsync,
|
|
20
|
+
getOrientationLockAsync,
|
|
21
|
+
Orientation,
|
|
22
|
+
OrientationLock,
|
|
23
|
+
type EventSubscription,
|
|
24
|
+
type ScreenOrientationState,
|
|
25
|
+
} from '../../core';
|
|
26
|
+
|
|
27
|
+
export function createScreenOrientation(): Accessor<ScreenOrientationState> {
|
|
28
|
+
const [screenOrientation, setScreenOrientation] =
|
|
29
|
+
createSignal<ScreenOrientationState>({
|
|
30
|
+
orientation: Orientation.UNKNOWN,
|
|
31
|
+
orientationLock: OrientationLock.UNKNOWN,
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
Promise.all([getOrientationAsync(), getOrientationLockAsync()]).then(
|
|
35
|
+
([orientation, orientationLock]) => {
|
|
36
|
+
setScreenOrientation({ orientation, orientationLock });
|
|
37
|
+
},
|
|
38
|
+
);
|
|
39
|
+
|
|
40
|
+
// Subscribed from the primitive body, not from an effect: React/Vue/Svelte start listening a
|
|
41
|
+
// tick after their seed runs, so a rotation landing in that window is lost. Both statements
|
|
42
|
+
// here run in one synchronous tick and nothing can interleave.
|
|
43
|
+
const subscription: EventSubscription = addOrientationChangeListener(
|
|
44
|
+
event => {
|
|
45
|
+
setScreenOrientation({
|
|
46
|
+
orientation: event.orientationInfo.orientation,
|
|
47
|
+
orientationLock: event.orientationLock,
|
|
48
|
+
});
|
|
49
|
+
},
|
|
50
|
+
);
|
|
51
|
+
|
|
52
|
+
onCleanup(() => {
|
|
53
|
+
subscription.remove();
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
return screenOrientation;
|
|
57
|
+
}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
// @symbiote-native/screen-orientation/svelte: the Svelte entry over the framework-agnostic core —
|
|
2
|
+
// mirrors the lifecycle-bucket naming convention of adapters/svelte/src/runes (never
|
|
3
|
+
// `hooks`/`composables`, those are React's and Vue's terms).
|
|
4
|
+
|
|
5
|
+
export { useScreenOrientation } from './runes/use-screen-orientation.svelte';
|
|
6
|
+
export * from '../core';
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
// Svelte lifecycle wiring over the framework-agnostic core (core/screen-orientation.ts). Seeds the
|
|
2
|
+
// initial value with one-shot getOrientationAsync()/getOrientationLockAsync() calls before the
|
|
3
|
+
// first native event fires, mirroring packages/network's useNetworkState.
|
|
4
|
+
//
|
|
5
|
+
// `.svelte.ts` extension: runes ($state/$effect) only work there outside a `.svelte` component;
|
|
6
|
+
// `runes/` is Svelte's name for the lifecycle bucket (React's `hooks/`, Vue's `composables/`).
|
|
7
|
+
// Returns a boxed getter, not a bare `$state`: Svelte 5 reactivity is lexically scoped to the
|
|
8
|
+
// declaring module and doesn't survive being returned raw from a plain function, so the caller
|
|
9
|
+
// reads `.current` like unwrapping Vue's `Ref` via `.value`.
|
|
10
|
+
import {
|
|
11
|
+
addOrientationChangeListener,
|
|
12
|
+
getOrientationAsync,
|
|
13
|
+
getOrientationLockAsync,
|
|
14
|
+
Orientation,
|
|
15
|
+
OrientationLock,
|
|
16
|
+
type EventSubscription,
|
|
17
|
+
type ScreenOrientationState,
|
|
18
|
+
} from '../../core';
|
|
19
|
+
|
|
20
|
+
export function useScreenOrientation(): {
|
|
21
|
+
readonly current: ScreenOrientationState;
|
|
22
|
+
} {
|
|
23
|
+
let screenOrientation = $state<ScreenOrientationState>({
|
|
24
|
+
orientation: Orientation.UNKNOWN,
|
|
25
|
+
orientationLock: OrientationLock.UNKNOWN,
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
$effect(() => {
|
|
29
|
+
// Write-only touches of `screenOrientation`, so the effect has no dependency on it and runs
|
|
30
|
+
// once per mount - the twin of Vue's onMounted/onUnmounted pair.
|
|
31
|
+
Promise.all([getOrientationAsync(), getOrientationLockAsync()]).then(
|
|
32
|
+
([orientation, orientationLock]) => {
|
|
33
|
+
screenOrientation = { orientation, orientationLock };
|
|
34
|
+
},
|
|
35
|
+
);
|
|
36
|
+
const subscription: EventSubscription = addOrientationChangeListener(
|
|
37
|
+
event => {
|
|
38
|
+
screenOrientation = {
|
|
39
|
+
orientation: event.orientationInfo.orientation,
|
|
40
|
+
orientationLock: event.orientationLock,
|
|
41
|
+
};
|
|
42
|
+
},
|
|
43
|
+
);
|
|
44
|
+
return () => subscription.remove();
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
return {
|
|
48
|
+
get current(): ScreenOrientationState {
|
|
49
|
+
return screenOrientation;
|
|
50
|
+
},
|
|
51
|
+
};
|
|
52
|
+
}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
// Pulls in svelte's ambient global declarations ($state/$effect/...) for this package's tsc
|
|
2
|
+
// program. adapters/svelte gets these for free because render.ts does a real value import from
|
|
3
|
+
// 'svelte' (any file in a program importing a module loads its ambient globals for the whole
|
|
4
|
+
// program); this package has no such import, so a triple-slash reference does the same job
|
|
5
|
+
// explicitly rather than relying on an incidental side-effect.
|
|
6
|
+
/// <reference types="svelte" />
|
package/src/vue/index.ts
CHANGED
|
@@ -1,26 +1,4 @@
|
|
|
1
1
|
// @symbiote-native/screen-orientation/vue: the Vue entry over the framework-agnostic core.
|
|
2
2
|
|
|
3
3
|
export { useScreenOrientation } from './composables/use-screen-orientation';
|
|
4
|
-
export
|
|
5
|
-
lockAsync,
|
|
6
|
-
lockPlatformAsync,
|
|
7
|
-
unlockAsync,
|
|
8
|
-
getOrientationAsync,
|
|
9
|
-
getOrientationLockAsync,
|
|
10
|
-
getPlatformOrientationLockAsync,
|
|
11
|
-
supportsOrientationLockAsync,
|
|
12
|
-
addOrientationChangeListener,
|
|
13
|
-
removeOrientationChangeListeners,
|
|
14
|
-
removeOrientationChangeListener,
|
|
15
|
-
Orientation,
|
|
16
|
-
OrientationLock,
|
|
17
|
-
SizeClassIOS,
|
|
18
|
-
WebOrientationLock,
|
|
19
|
-
WebOrientation,
|
|
20
|
-
type PlatformOrientationInfo,
|
|
21
|
-
type ScreenOrientationInfo,
|
|
22
|
-
type OrientationChangeEvent,
|
|
23
|
-
type OrientationChangeListener,
|
|
24
|
-
type ScreenOrientationState,
|
|
25
|
-
type EventSubscription,
|
|
26
|
-
} from '../core';
|
|
4
|
+
export * from '../core';
|