@symbiote-native/system-ui 0.0.1
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/LICENSE +21 -0
- package/README.md +138 -0
- package/build/angular/index.d.ts +1 -0
- package/build/angular/index.js +4 -0
- package/build/core/index.d.ts +1 -0
- package/build/core/index.js +1 -0
- package/build/core/native-module.d.ts +6 -0
- package/build/core/native-module.js +3 -0
- package/build/core/system-ui.d.ts +22 -0
- package/build/core/system-ui.js +33 -0
- package/build/react/index.d.ts +1 -0
- package/build/react/index.js +6 -0
- package/build/vue/index.d.ts +1 -0
- package/build/vue/index.js +4 -0
- package/build-ngc/angular/index.d.ts +1 -0
- package/build-ngc/angular/index.js +5 -0
- package/build-ngc/angular/index.js.map +1 -0
- package/build-ngc/core/index.d.ts +1 -0
- package/build-ngc/core/index.js +2 -0
- package/build-ngc/core/index.js.map +1 -0
- package/build-ngc/core/native-module.d.ts +6 -0
- package/build-ngc/core/native-module.js +4 -0
- package/build-ngc/core/native-module.js.map +1 -0
- package/build-ngc/core/system-ui.d.ts +22 -0
- package/build-ngc/core/system-ui.js +34 -0
- package/build-ngc/core/system-ui.js.map +1 -0
- package/native-link.json +12 -0
- package/package.json +107 -0
- package/src/angular/index.ts +4 -0
- package/src/core/index.ts +1 -0
- package/src/core/native-module.ts +16 -0
- package/src/core/system-ui.test.ts +62 -0
- package/src/core/system-ui.ts +40 -0
- package/src/react/index.ts +6 -0
- package/src/vue/index.ts +4 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 A. Prokopenko
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
# @symbiote-native/system-ui
|
|
2
|
+
|
|
3
|
+
A wrapper package for [SymbioteNative](../../README.md) that makes
|
|
4
|
+
[`expo-system-ui`](https://github.com/expo/expo/tree/main/packages/expo-system-ui)
|
|
5
|
+
— setting and reading the root view's background color — usable from **every** adapter,
|
|
6
|
+
React, Vue, and Angular, not just React. Like
|
|
7
|
+
[`@symbiote-native/device`](../device) and [`@symbiote-native/local-auth`](../local-auth) and
|
|
8
|
+
unlike this repo's stateful Expo wrapper ([`@symbiote-native/sensors`](../sensors), an
|
|
9
|
+
`EventEmitter` + live-subscription surface), both exports here are one-shot async calls with no
|
|
10
|
+
per-instance state, so there is no hook/composable/service to wrap — the React, Vue, and
|
|
11
|
+
Angular entry points are plain re-exports of the same `core`.
|
|
12
|
+
|
|
13
|
+
## Install
|
|
14
|
+
|
|
15
|
+
```bash
|
|
16
|
+
npm install @symbiote-native/system-ui
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
`expo-system-ui` and `expo-modules-core` come along as regular dependencies, pinned to exact
|
|
20
|
+
versions — never install either yourself, and never add the `expo` meta-package to your project
|
|
21
|
+
(it bundles its own Metro/Babel pipeline, which conflicts with this project's own).
|
|
22
|
+
|
|
23
|
+
## Required one-time step: native autolinking wiring
|
|
24
|
+
|
|
25
|
+
Unlike a plain RN native module, `expo-system-ui`'s native code is discovered by
|
|
26
|
+
`expo-modules-autolinking`, not RN's own `react-native.config.cjs` mechanism — this needs wiring
|
|
27
|
+
into the native host app **once**, covering this package and every other `expo-modules-core`
|
|
28
|
+
package with zero further changes:
|
|
29
|
+
|
|
30
|
+
| Platform | Touches |
|
|
31
|
+
|---|---|
|
|
32
|
+
| iOS | `ios/Podfile` — add `use_expo_modules!` |
|
|
33
|
+
| iOS | `AppDelegate.swift` — Expo's runtime-bootstrap hook |
|
|
34
|
+
| Android | `settings.gradle` / `app/build.gradle` — resolve and include the Expo Gradle projects |
|
|
35
|
+
| 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) |
|
|
36
|
+
|
|
37
|
+
Full mechanics live in the `symbiote-expo-native-module` project skill. Reference
|
|
38
|
+
implementation: `examples/expo-react/ios/Podfile` and
|
|
39
|
+
`examples/expo-react/android/app/src/main/java/com/canaryexpo/MainApplication.kt`.
|
|
40
|
+
|
|
41
|
+
`expo-system-ui` needs no runtime permission on either platform — it only sets/reads a stored
|
|
42
|
+
background color, nothing gated by a permission prompt.
|
|
43
|
+
|
|
44
|
+
## Shape
|
|
45
|
+
|
|
46
|
+
```
|
|
47
|
+
src/core/ setBackgroundColorAsync / getBackgroundColorAsync. native-module.ts resolves the
|
|
48
|
+
native module via expo-modules-core's requireNativeModule.
|
|
49
|
+
src/react/ @symbiote-native/system-ui/react — export * from '../core'
|
|
50
|
+
src/vue/ @symbiote-native/system-ui/vue — export * from '../core'
|
|
51
|
+
src/angular/ @symbiote-native/system-ui/angular — export * from '../core'
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
No per-adapter lifecycle wrapper exists because there's nothing to subscribe to or clean up —
|
|
55
|
+
each adapter entry is a single-file re-export.
|
|
56
|
+
|
|
57
|
+
## Use it
|
|
58
|
+
|
|
59
|
+
```tsx
|
|
60
|
+
// React
|
|
61
|
+
import { setBackgroundColorAsync } from '@symbiote-native/system-ui/react';
|
|
62
|
+
|
|
63
|
+
setBackgroundColorAsync('black');
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
```vue
|
|
67
|
+
<!-- Vue -->
|
|
68
|
+
<script setup lang="ts">
|
|
69
|
+
import { onMounted } from 'vue';
|
|
70
|
+
import { setBackgroundColorAsync } from '@symbiote-native/system-ui/vue';
|
|
71
|
+
|
|
72
|
+
onMounted(() => {
|
|
73
|
+
void setBackgroundColorAsync('black');
|
|
74
|
+
});
|
|
75
|
+
</script>
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
```ts
|
|
79
|
+
// Angular
|
|
80
|
+
import { Component } from '@angular/core';
|
|
81
|
+
import { setBackgroundColorAsync } from '@symbiote-native/system-ui/angular';
|
|
82
|
+
|
|
83
|
+
@Component({ standalone: true, template: `` })
|
|
84
|
+
export class RootComponent {
|
|
85
|
+
constructor() {
|
|
86
|
+
void setBackgroundColorAsync('black');
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
There's no per-instance service to `inject()` in the Angular case — both functions are plain
|
|
92
|
+
exports off the core package, called straight in the constructor or wherever the app's root is
|
|
93
|
+
set up. These snippets are not yet demoed in a real canary screen — no `SystemUiScreen.*` exists
|
|
94
|
+
yet in `examples/expo-*` — so treat them as realistic reference code, not a trimmed-down copy of
|
|
95
|
+
a running demo.
|
|
96
|
+
|
|
97
|
+
## API
|
|
98
|
+
|
|
99
|
+
Two one-shot async functions, no event stream, no per-instance state — so the React/Vue/Angular
|
|
100
|
+
entry points above are plain re-exports of `core` with nothing adapter-specific to add.
|
|
101
|
+
|
|
102
|
+
```ts
|
|
103
|
+
setBackgroundColorAsync(color: ColorValue | null): Promise<void>
|
|
104
|
+
getBackgroundColorAsync(): Promise<ColorValue | null>
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
```ts
|
|
108
|
+
import { getBackgroundColorAsync, setBackgroundColorAsync } from '@symbiote-native/system-ui';
|
|
109
|
+
// or the framework-scoped entry points — identical surface, re-exported verbatim:
|
|
110
|
+
import { setBackgroundColorAsync } from '@symbiote-native/system-ui/react';
|
|
111
|
+
import { setBackgroundColorAsync } from '@symbiote-native/system-ui/vue';
|
|
112
|
+
import { setBackgroundColorAsync } from '@symbiote-native/system-ui/angular';
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
## Notes
|
|
116
|
+
|
|
117
|
+
- **`setBackgroundColorAsync(null)` clears the override** rather than setting an actual color —
|
|
118
|
+
it's passed straight through to the native module without running `processColor`.
|
|
119
|
+
- **On web, the raw `ColorValue` is passed through untouched** instead of being run through RN's
|
|
120
|
+
`processColor` — matching upstream, since `processColor` is a native-color-parsing step that
|
|
121
|
+
doesn't apply on that platform.
|
|
122
|
+
- **On iOS/Android, a non-null color is run through RN's own `processColor` before reaching the
|
|
123
|
+
native module** — the same conversion RN's style pipeline uses internally.
|
|
124
|
+
|
|
125
|
+
## Test it
|
|
126
|
+
|
|
127
|
+
No Fabric/Descriptor angle at all — both exports here are one-shot async calls, never a view or
|
|
128
|
+
per-instance state. Tests inject a fake native-module object in place of the real
|
|
129
|
+
`requireNativeModule` resolution (`src/core/system-ui.test.ts`, `vitest`) — no `installFabric()`,
|
|
130
|
+
no ViewConfig. Native rendering itself is verified on-device (see the parent
|
|
131
|
+
[README](../../README.md) for the project's testing model).
|
|
132
|
+
|
|
133
|
+
Native autolinking wiring for `expo-modules-core` packages is already done in the four Expo
|
|
134
|
+
canary apps (`examples/expo-react`, `examples/expo-vue-sfc`, `examples/expo-vue-tsx`,
|
|
135
|
+
`examples/expo-angular`) via `@symbiote-native/local-auth`/`@symbiote-native/sensors` — this
|
|
136
|
+
package reuses that same wiring with zero further app-side changes, since
|
|
137
|
+
`expo-modules-autolinking` discovers any `expo-modules-core` package already present in
|
|
138
|
+
`node_modules`. A dedicated `SystemUiScreen` demo has not been wired into those canaries yet.
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from '../core';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { getBackgroundColorAsync, setBackgroundColorAsync } from './system-ui';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { getBackgroundColorAsync, setBackgroundColorAsync } from './system-ui';
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import type { ColorValue, ProcessedColorValue } from 'react-native';
|
|
2
|
+
export type INativeSystemUIModule = {
|
|
3
|
+
setBackgroundColorAsync(color: ColorValue | ProcessedColorValue | null | undefined): Promise<void>;
|
|
4
|
+
getBackgroundColorAsync(): Promise<ColorValue | null>;
|
|
5
|
+
};
|
|
6
|
+
export declare const expoSystemUI: INativeSystemUIModule;
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import type { ColorValue } from 'react-native';
|
|
2
|
+
/**
|
|
3
|
+
* Changes the root view background color. Call this outside of your component tree, e.g. in
|
|
4
|
+
* the root file, since it affects the whole app.
|
|
5
|
+
* @example
|
|
6
|
+
* ```ts
|
|
7
|
+
* setBackgroundColorAsync("black");
|
|
8
|
+
* ```
|
|
9
|
+
* @param color Any valid [CSS 3 (SVG) color](http://www.w3.org/TR/css3-color/#svg-color), or
|
|
10
|
+
* `null` to clear the override.
|
|
11
|
+
*/
|
|
12
|
+
export declare function setBackgroundColorAsync(color: ColorValue | null): Promise<void>;
|
|
13
|
+
/**
|
|
14
|
+
* Gets the root view background color.
|
|
15
|
+
* @example
|
|
16
|
+
* ```ts
|
|
17
|
+
* const color = await getBackgroundColorAsync();
|
|
18
|
+
* ```
|
|
19
|
+
* @returns Current root view background color in hex format. `null` if the background color is
|
|
20
|
+
* not set.
|
|
21
|
+
*/
|
|
22
|
+
export declare function getBackgroundColorAsync(): Promise<ColorValue | null>;
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { Platform, processColor } from 'react-native';
|
|
2
|
+
import { expoSystemUI } from './native-module';
|
|
3
|
+
/**
|
|
4
|
+
* Changes the root view background color. Call this outside of your component tree, e.g. in
|
|
5
|
+
* the root file, since it affects the whole app.
|
|
6
|
+
* @example
|
|
7
|
+
* ```ts
|
|
8
|
+
* setBackgroundColorAsync("black");
|
|
9
|
+
* ```
|
|
10
|
+
* @param color Any valid [CSS 3 (SVG) color](http://www.w3.org/TR/css3-color/#svg-color), or
|
|
11
|
+
* `null` to clear the override.
|
|
12
|
+
*/
|
|
13
|
+
export async function setBackgroundColorAsync(color) {
|
|
14
|
+
if (color == null) {
|
|
15
|
+
return await expoSystemUI.setBackgroundColorAsync(null);
|
|
16
|
+
}
|
|
17
|
+
else {
|
|
18
|
+
const colorNumber = Platform.OS === 'web' ? color : processColor(color);
|
|
19
|
+
return await expoSystemUI.setBackgroundColorAsync(colorNumber);
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Gets the root view background color.
|
|
24
|
+
* @example
|
|
25
|
+
* ```ts
|
|
26
|
+
* const color = await getBackgroundColorAsync();
|
|
27
|
+
* ```
|
|
28
|
+
* @returns Current root view background color in hex format. `null` if the background color is
|
|
29
|
+
* not set.
|
|
30
|
+
*/
|
|
31
|
+
export async function getBackgroundColorAsync() {
|
|
32
|
+
return await expoSystemUI.getBackgroundColorAsync();
|
|
33
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from '../core';
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
// @symbiote-native/system-ui/react: the React entry over the framework-agnostic core. Both
|
|
2
|
+
// exports are plain async functions with no per-instance state and no event stream (unlike
|
|
3
|
+
// @symbiote-native/sensors) — there is nothing for a hook to wrap, so this is a plain
|
|
4
|
+
// re-export, mirroring how @symbiote-native/device's React entry passes its own free
|
|
5
|
+
// functions through untouched.
|
|
6
|
+
export * from '../core';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from '../core';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from '../core';
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
// @symbiote-native/system-ui/angular: the Angular entry over the framework-agnostic core.
|
|
2
|
+
// Same reasoning as the React/Vue entries — no per-instance state or event stream to wrap in a
|
|
3
|
+
// service, so this is a plain re-export.
|
|
4
|
+
export * from '../core';
|
|
5
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/angular/index.ts"],"names":[],"mappings":"AAAA,0FAA0F;AAC1F,+FAA+F;AAC/F,yCAAyC;AACzC,cAAc,SAAS,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { getBackgroundColorAsync, setBackgroundColorAsync } from './system-ui';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/core/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,uBAAuB,EAAE,uBAAuB,EAAE,MAAM,aAAa,CAAC"}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import type { ColorValue, ProcessedColorValue } from 'react-native';
|
|
2
|
+
export type INativeSystemUIModule = {
|
|
3
|
+
setBackgroundColorAsync(color: ColorValue | ProcessedColorValue | null | undefined): Promise<void>;
|
|
4
|
+
getBackgroundColorAsync(): Promise<ColorValue | null>;
|
|
5
|
+
};
|
|
6
|
+
export declare const expoSystemUI: INativeSystemUIModule;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"native-module.js","sourceRoot":"","sources":["../../src/core/native-module.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,mBAAmB,EAAE,MAAM,mBAAmB,CAAC;AAExD,MAAM,0BAA0B,GAAG,cAAc,CAAC;AAYlD,MAAM,CAAC,MAAM,YAAY,GAAG,mBAAmB,CAAwB,0BAA0B,CAAC,CAAC"}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import type { ColorValue } from 'react-native';
|
|
2
|
+
/**
|
|
3
|
+
* Changes the root view background color. Call this outside of your component tree, e.g. in
|
|
4
|
+
* the root file, since it affects the whole app.
|
|
5
|
+
* @example
|
|
6
|
+
* ```ts
|
|
7
|
+
* setBackgroundColorAsync("black");
|
|
8
|
+
* ```
|
|
9
|
+
* @param color Any valid [CSS 3 (SVG) color](http://www.w3.org/TR/css3-color/#svg-color), or
|
|
10
|
+
* `null` to clear the override.
|
|
11
|
+
*/
|
|
12
|
+
export declare function setBackgroundColorAsync(color: ColorValue | null): Promise<void>;
|
|
13
|
+
/**
|
|
14
|
+
* Gets the root view background color.
|
|
15
|
+
* @example
|
|
16
|
+
* ```ts
|
|
17
|
+
* const color = await getBackgroundColorAsync();
|
|
18
|
+
* ```
|
|
19
|
+
* @returns Current root view background color in hex format. `null` if the background color is
|
|
20
|
+
* not set.
|
|
21
|
+
*/
|
|
22
|
+
export declare function getBackgroundColorAsync(): Promise<ColorValue | null>;
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { Platform, processColor } from 'react-native';
|
|
2
|
+
import { expoSystemUI } from './native-module';
|
|
3
|
+
/**
|
|
4
|
+
* Changes the root view background color. Call this outside of your component tree, e.g. in
|
|
5
|
+
* the root file, since it affects the whole app.
|
|
6
|
+
* @example
|
|
7
|
+
* ```ts
|
|
8
|
+
* setBackgroundColorAsync("black");
|
|
9
|
+
* ```
|
|
10
|
+
* @param color Any valid [CSS 3 (SVG) color](http://www.w3.org/TR/css3-color/#svg-color), or
|
|
11
|
+
* `null` to clear the override.
|
|
12
|
+
*/
|
|
13
|
+
export async function setBackgroundColorAsync(color) {
|
|
14
|
+
if (color == null) {
|
|
15
|
+
return await expoSystemUI.setBackgroundColorAsync(null);
|
|
16
|
+
}
|
|
17
|
+
else {
|
|
18
|
+
const colorNumber = Platform.OS === 'web' ? color : processColor(color);
|
|
19
|
+
return await expoSystemUI.setBackgroundColorAsync(colorNumber);
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Gets the root view background color.
|
|
24
|
+
* @example
|
|
25
|
+
* ```ts
|
|
26
|
+
* const color = await getBackgroundColorAsync();
|
|
27
|
+
* ```
|
|
28
|
+
* @returns Current root view background color in hex format. `null` if the background color is
|
|
29
|
+
* not set.
|
|
30
|
+
*/
|
|
31
|
+
export async function getBackgroundColorAsync() {
|
|
32
|
+
return await expoSystemUI.getBackgroundColorAsync();
|
|
33
|
+
}
|
|
34
|
+
//# sourceMappingURL=system-ui.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"system-ui.js","sourceRoot":"","sources":["../../src/core/system-ui.ts"],"names":[],"mappings":"AAKA,OAAO,EAAE,QAAQ,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AAEtD,OAAO,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AAE/C;;;;;;;;;GASG;AACH,MAAM,CAAC,KAAK,UAAU,uBAAuB,CAAC,KAAwB;IACpE,IAAI,KAAK,IAAI,IAAI,EAAE,CAAC;QAClB,OAAO,MAAM,YAAY,CAAC,uBAAuB,CAAC,IAAI,CAAC,CAAC;IAC1D,CAAC;SAAM,CAAC;QACN,MAAM,WAAW,GAAG,QAAQ,CAAC,EAAE,KAAK,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,YAAY,CAAC,KAAK,CAAC,CAAC;QACxE,OAAO,MAAM,YAAY,CAAC,uBAAuB,CAAC,WAAW,CAAC,CAAC;IACjE,CAAC;AACH,CAAC;AAED;;;;;;;;GAQG;AACH,MAAM,CAAC,KAAK,UAAU,uBAAuB;IAC3C,OAAO,MAAM,YAAY,CAAC,uBAAuB,EAAE,CAAC;AACtD,CAAC"}
|
package/native-link.json
ADDED
package/package.json
ADDED
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@symbiote-native/system-ui",
|
|
3
|
+
"version": "0.0.1",
|
|
4
|
+
"description": "expo-system-ui wrapped for SymbioteNative — one framework-agnostic core, built once and reachable from the React, Vue, and Angular adapters. Sets and reads the root view's background color.",
|
|
5
|
+
"license": "MIT",
|
|
6
|
+
"repository": {
|
|
7
|
+
"type": "git",
|
|
8
|
+
"url": "git+https://github.com/OneEyed1366/symbiote-native.git",
|
|
9
|
+
"directory": "packages/system-ui"
|
|
10
|
+
},
|
|
11
|
+
"homepage": "https://github.com/OneEyed1366/symbiote-native/tree/master/packages/system-ui#readme",
|
|
12
|
+
"bugs": {
|
|
13
|
+
"url": "https://github.com/OneEyed1366/symbiote-native/issues"
|
|
14
|
+
},
|
|
15
|
+
"author": "Andrey Prokopenko <psevdoproger@gmail.com>",
|
|
16
|
+
"type": "module",
|
|
17
|
+
"main": "./build/core/index.js",
|
|
18
|
+
"module": "./build/core/index.js",
|
|
19
|
+
"types": "./build/core/index.d.ts",
|
|
20
|
+
"exports": {
|
|
21
|
+
".": {
|
|
22
|
+
"types": "./build/core/index.d.ts",
|
|
23
|
+
"default": "./build/core/index.js"
|
|
24
|
+
},
|
|
25
|
+
"./vue": {
|
|
26
|
+
"types": "./build/vue/index.d.ts",
|
|
27
|
+
"default": "./build/vue/index.js"
|
|
28
|
+
},
|
|
29
|
+
"./react": {
|
|
30
|
+
"types": "./build/react/index.d.ts",
|
|
31
|
+
"default": "./build/react/index.js"
|
|
32
|
+
},
|
|
33
|
+
"./angular": {
|
|
34
|
+
"types": "./build-ngc/angular/index.d.ts",
|
|
35
|
+
"react-native": "./build-ngc/angular/index.js",
|
|
36
|
+
"default": "./src/angular/index.ts"
|
|
37
|
+
}
|
|
38
|
+
},
|
|
39
|
+
"files": [
|
|
40
|
+
"src",
|
|
41
|
+
"build",
|
|
42
|
+
"build-ngc",
|
|
43
|
+
"native-link.json"
|
|
44
|
+
],
|
|
45
|
+
"publishConfig": {
|
|
46
|
+
"access": "public"
|
|
47
|
+
},
|
|
48
|
+
"dependencies": {
|
|
49
|
+
"expo-system-ui": "57.0.2",
|
|
50
|
+
"expo-modules-core": "57.0.5"
|
|
51
|
+
},
|
|
52
|
+
"peerDependencies": {
|
|
53
|
+
"@symbiote-native/engine": ">=0.1.7",
|
|
54
|
+
"@angular/core": ">=20",
|
|
55
|
+
"@vue/runtime-core": "^3.5.13",
|
|
56
|
+
"react": ">=19.0.0",
|
|
57
|
+
"react-native": ">=0.86",
|
|
58
|
+
"vue": ">=3.5.0",
|
|
59
|
+
"@symbiote-native/angular": "0.6.1",
|
|
60
|
+
"@symbiote-native/react": "0.2.8",
|
|
61
|
+
"@symbiote-native/vue": "0.3.8"
|
|
62
|
+
},
|
|
63
|
+
"peerDependenciesMeta": {
|
|
64
|
+
"@symbiote-native/angular": {
|
|
65
|
+
"optional": true
|
|
66
|
+
},
|
|
67
|
+
"@symbiote-native/react": {
|
|
68
|
+
"optional": true
|
|
69
|
+
},
|
|
70
|
+
"@symbiote-native/vue": {
|
|
71
|
+
"optional": true
|
|
72
|
+
},
|
|
73
|
+
"@angular/core": {
|
|
74
|
+
"optional": true
|
|
75
|
+
},
|
|
76
|
+
"@vue/runtime-core": {
|
|
77
|
+
"optional": true
|
|
78
|
+
},
|
|
79
|
+
"react": {
|
|
80
|
+
"optional": true
|
|
81
|
+
},
|
|
82
|
+
"vue": {
|
|
83
|
+
"optional": true
|
|
84
|
+
}
|
|
85
|
+
},
|
|
86
|
+
"devDependencies": {
|
|
87
|
+
"@angular/compiler": "^22",
|
|
88
|
+
"@angular/compiler-cli": "^22",
|
|
89
|
+
"@angular/core": "^22",
|
|
90
|
+
"@types/node": "^26.0.0",
|
|
91
|
+
"@types/react": "^19.2.0",
|
|
92
|
+
"@vue/runtime-core": "^3.5.13",
|
|
93
|
+
"react": "19.2.3",
|
|
94
|
+
"typescript": "~6.0.0",
|
|
95
|
+
"@symbiote-native/angular": "0.6.1",
|
|
96
|
+
"@symbiote-native/react": "0.2.8",
|
|
97
|
+
"@symbiote-native/vue": "0.3.8",
|
|
98
|
+
"@symbiote-native/test-utils": "0.1.6",
|
|
99
|
+
"@symbiote-native/engine": "0.1.7"
|
|
100
|
+
},
|
|
101
|
+
"scripts": {
|
|
102
|
+
"typecheck": "tsc --build",
|
|
103
|
+
"clean": "rm -rf build-ngc",
|
|
104
|
+
"ng:build": "pnpm run clean && ngc -p tsconfig.angular.json",
|
|
105
|
+
"format": "prettier --write \"src/**/*.{ts,tsx}\""
|
|
106
|
+
}
|
|
107
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { getBackgroundColorAsync, setBackgroundColorAsync } from './system-ui';
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type { ColorValue, ProcessedColorValue } from 'react-native';
|
|
2
|
+
import { requireNativeModule } from 'expo-modules-core';
|
|
3
|
+
|
|
4
|
+
const EXPO_SYSTEM_UI_MODULE_NAME = 'ExpoSystemUI';
|
|
5
|
+
|
|
6
|
+
// The color argument accepts everything system-ui.ts can pass it: the raw ColorValue on web,
|
|
7
|
+
// or RN's own processColor() result (a number, an OpaqueColorValue, or undefined) on
|
|
8
|
+
// iOS/Android.
|
|
9
|
+
export type INativeSystemUIModule = {
|
|
10
|
+
setBackgroundColorAsync(
|
|
11
|
+
color: ColorValue | ProcessedColorValue | null | undefined,
|
|
12
|
+
): Promise<void>;
|
|
13
|
+
getBackgroundColorAsync(): Promise<ColorValue | null>;
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
export const expoSystemUI = requireNativeModule<INativeSystemUIModule>(EXPO_SYSTEM_UI_MODULE_NAME);
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import { afterEach, describe, expect, it, vi } from 'vitest';
|
|
2
|
+
|
|
3
|
+
const FAKE_NATIVE_SYSTEM_UI = {
|
|
4
|
+
setBackgroundColorAsync: vi.fn(async () => undefined),
|
|
5
|
+
getBackgroundColorAsync: vi.fn(async () => '#000000'),
|
|
6
|
+
};
|
|
7
|
+
|
|
8
|
+
// The real ExpoSystemUI native module only exists on device — resolving it via
|
|
9
|
+
// requireNativeModule() at import time would throw in this headless test run, so the
|
|
10
|
+
// module-lookup file is faked in place of expo-modules-core's runtime resolution, the same
|
|
11
|
+
// pattern packages/device/src/core/device.test.ts uses.
|
|
12
|
+
vi.mock('./native-module', () => ({
|
|
13
|
+
expoSystemUI: FAKE_NATIVE_SYSTEM_UI,
|
|
14
|
+
}));
|
|
15
|
+
|
|
16
|
+
// react-native's real Platform module reads native constants that don't exist in this headless
|
|
17
|
+
// run; processColor is stubbed to a simple, observable transform so the two branches
|
|
18
|
+
// (color == null / Platform.OS === 'web' / native processColor) are each independently provable.
|
|
19
|
+
vi.mock('react-native', () => ({
|
|
20
|
+
Platform: { OS: 'ios' },
|
|
21
|
+
processColor: vi.fn((color: string) => `processed(${color})`),
|
|
22
|
+
}));
|
|
23
|
+
|
|
24
|
+
const { getBackgroundColorAsync, setBackgroundColorAsync } = await import('./system-ui');
|
|
25
|
+
const { Platform, processColor } = await import('react-native');
|
|
26
|
+
|
|
27
|
+
afterEach(() => {
|
|
28
|
+
vi.clearAllMocks();
|
|
29
|
+
Platform.OS = 'ios';
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
describe('setBackgroundColorAsync', () => {
|
|
33
|
+
it('passes null straight through when color is null', async () => {
|
|
34
|
+
await setBackgroundColorAsync(null);
|
|
35
|
+
|
|
36
|
+
expect(processColor).not.toHaveBeenCalled();
|
|
37
|
+
expect(FAKE_NATIVE_SYSTEM_UI.setBackgroundColorAsync).toHaveBeenCalledWith(null);
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
it('runs a non-null color through processColor on native platforms', async () => {
|
|
41
|
+
await setBackgroundColorAsync('tomato');
|
|
42
|
+
|
|
43
|
+
expect(processColor).toHaveBeenCalledWith('tomato');
|
|
44
|
+
expect(FAKE_NATIVE_SYSTEM_UI.setBackgroundColorAsync).toHaveBeenCalledWith('processed(tomato)');
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
it('passes the raw color straight through on web, skipping processColor', async () => {
|
|
48
|
+
Platform.OS = 'web';
|
|
49
|
+
|
|
50
|
+
await setBackgroundColorAsync('tomato');
|
|
51
|
+
|
|
52
|
+
expect(processColor).not.toHaveBeenCalled();
|
|
53
|
+
expect(FAKE_NATIVE_SYSTEM_UI.setBackgroundColorAsync).toHaveBeenCalledWith('tomato');
|
|
54
|
+
});
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
describe('getBackgroundColorAsync', () => {
|
|
58
|
+
it('delegates to the native module', async () => {
|
|
59
|
+
await expect(getBackgroundColorAsync()).resolves.toBe('#000000');
|
|
60
|
+
expect(FAKE_NATIVE_SYSTEM_UI.getBackgroundColorAsync).toHaveBeenCalled();
|
|
61
|
+
});
|
|
62
|
+
});
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
// Hand-ported from .vendors/expo/packages/expo-system-ui/src/SystemUI.ts (sdk-57), verbatim
|
|
2
|
+
// apart from resolving the native module through native-module.ts (this repo's convention,
|
|
3
|
+
// matching local-auth/device/cellular) instead of a bare `import ExpoSystemUI from
|
|
4
|
+
// './ExpoSystemUI'`.
|
|
5
|
+
import type { ColorValue } from 'react-native';
|
|
6
|
+
import { Platform, processColor } from 'react-native';
|
|
7
|
+
|
|
8
|
+
import { expoSystemUI } from './native-module';
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Changes the root view background color. Call this outside of your component tree, e.g. in
|
|
12
|
+
* the root file, since it affects the whole app.
|
|
13
|
+
* @example
|
|
14
|
+
* ```ts
|
|
15
|
+
* setBackgroundColorAsync("black");
|
|
16
|
+
* ```
|
|
17
|
+
* @param color Any valid [CSS 3 (SVG) color](http://www.w3.org/TR/css3-color/#svg-color), or
|
|
18
|
+
* `null` to clear the override.
|
|
19
|
+
*/
|
|
20
|
+
export async function setBackgroundColorAsync(color: ColorValue | null): Promise<void> {
|
|
21
|
+
if (color == null) {
|
|
22
|
+
return await expoSystemUI.setBackgroundColorAsync(null);
|
|
23
|
+
} else {
|
|
24
|
+
const colorNumber = Platform.OS === 'web' ? color : processColor(color);
|
|
25
|
+
return await expoSystemUI.setBackgroundColorAsync(colorNumber);
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Gets the root view background color.
|
|
31
|
+
* @example
|
|
32
|
+
* ```ts
|
|
33
|
+
* const color = await getBackgroundColorAsync();
|
|
34
|
+
* ```
|
|
35
|
+
* @returns Current root view background color in hex format. `null` if the background color is
|
|
36
|
+
* not set.
|
|
37
|
+
*/
|
|
38
|
+
export async function getBackgroundColorAsync(): Promise<ColorValue | null> {
|
|
39
|
+
return await expoSystemUI.getBackgroundColorAsync();
|
|
40
|
+
}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
// @symbiote-native/system-ui/react: the React entry over the framework-agnostic core. Both
|
|
2
|
+
// exports are plain async functions with no per-instance state and no event stream (unlike
|
|
3
|
+
// @symbiote-native/sensors) — there is nothing for a hook to wrap, so this is a plain
|
|
4
|
+
// re-export, mirroring how @symbiote-native/device's React entry passes its own free
|
|
5
|
+
// functions through untouched.
|
|
6
|
+
export * from '../core';
|
package/src/vue/index.ts
ADDED