@symbiote-native/keep-awake 0.2.0 → 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -2,8 +2,8 @@
2
2
 
3
3
  Port of [`expo-keep-awake`](https://docs.expo.dev/versions/latest/sdk/keep-awake/) for
4
4
  [SymbioteNative](../../README.md) — keeps the screen on for the lifetime of a mounted
5
- component/composable/service, reachable from every adapter (React, Vue, Angular), not just
6
- React.
5
+ component/composable/service, reachable from every adapter (React, Vue, Svelte, Solid, Angular),
6
+ not just React.
7
7
 
8
8
  Built the same way as [`@symbiote-native/battery`](../battery) and
9
9
  [`@symbiote-native/device`](../device), an `expo-modules-core`-based wrapper (see the
@@ -31,18 +31,20 @@ into the native host app **once**, covering this package and every other `expo-m
31
31
  package (`@symbiote-native/battery`, `@symbiote-native/device`, `@symbiote-native/sensors`, …)
32
32
  with zero further changes:
33
33
 
34
- | Platform | Touches |
35
- |---|---|
36
- | iOS | `ios/Podfile` — add `use_expo_modules!` |
37
- | iOS | `AppDelegate.swift` — Expo's runtime-bootstrap hook |
38
- | Android | `settings.gradle` / `app/build.gradle` — resolve and include the Expo Gradle projects |
39
- | 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) |
34
+ | Platform | Touches |
35
+ | -------- | --------------------------------------------------------------------------------------------------------------------------------------------------- |
36
+ | iOS | `ios/Podfile` — add `use_expo_modules!` |
37
+ | iOS | `AppDelegate.swift` — Expo's runtime-bootstrap hook |
38
+ | Android | `settings.gradle` / `app/build.gradle` — resolve and include the Expo Gradle projects |
39
+ | 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
40
 
41
41
  The recurring per-package half of the Android wiring (`app/build.gradle`'s
42
42
  `implementation project(':expo-keep-awake')` line and `MainApplication.kt`'s module-name map
43
- entry) is automated by this package's own `postinstall` script via
44
- `@symbiote-native/expo-modules-link` — see that package's README for how the `native-link.json`
45
- manifest above drives it. Full mechanics — the Podfile pieces that normally ship inside the
43
+ entry) is automated by installing `@symbiote-native/expo-modules-link` in the consuming app —
44
+ its own `postinstall` hook scans `node_modules` for every installed package's `native-link.json`
45
+ (this one included) and regenerates the registration blocks. This package ships no `postinstall`
46
+ of its own — `native-link.json` above is passive data the aggregator reads. See that package's
47
+ README for the full mechanism. Full mechanics — the Podfile pieces that normally ship inside the
46
48
  `expo` package, the `expo` peer-dependency exclusion list — live in the
47
49
  `symbiote-expo-native-module` skill.
48
50
 
@@ -59,15 +61,18 @@ src/core/ keep-awake.ts — isAvailableAsync/activateKeepAwakeAsyn
59
61
  KeepAwakeOptions, hand-ported from KeepAwake.types.ts.
60
62
  src/react/hooks/ @symbiote-native/keep-awake/react — useKeepAwake
61
63
  src/vue/composables/ @symbiote-native/keep-awake/vue — useKeepAwake
64
+ src/svelte/runes/ @symbiote-native/keep-awake/svelte — useKeepAwake
65
+ src/solid/primitives/ @symbiote-native/keep-awake/solid — createKeepAwake (Solid says
66
+ create*, not use*)
62
67
  src/angular/services/ @symbiote-native/keep-awake/angular — KeepAwakeService (`.connect()`,
63
68
  no return value — a pure side effect for the component's lifetime)
64
69
  ```
65
70
 
66
- Each adapter's hook/composable/service activates a keep-awake lock on mount and deactivates it on
67
- unmount, over the same `core` functions — the tag-generation and activate/deactivate lifecycle is
68
- written once and shared by all three. React uses `useId()` for its default per-instance tag,
69
- matching upstream; Vue and Angular have no `useId` equivalent, so both fall back to a small
70
- monotonically-incrementing module-local counter (`keep-awake-tag-1`, `keep-awake-tag-2`, …) when
71
+ Each adapter's hook/composable/rune/primitive/service activates a keep-awake lock on mount and
72
+ deactivates it on unmount, over the same `core` functions — the tag-generation and
73
+ activate/deactivate lifecycle is written once and shared by every adapter. React uses `useId()`
74
+ for its default per-instance tag, matching upstream; Vue, Svelte, Solid and Angular have no
75
+ `useId` equivalent, so they fall back to a small monotonically-incrementing module-local counter (`keep-awake-tag-1`, `keep-awake-tag-2`, …) when
71
76
  no explicit tag is given.
72
77
 
73
78
  ## Use it
@@ -95,12 +100,33 @@ useKeepAwake();
95
100
  </template>
96
101
  ```
97
102
 
103
+ ```svelte
104
+ <!-- Svelte -->
105
+ <script lang="ts">
106
+ import { useKeepAwake } from '@symbiote-native/keep-awake/svelte';
107
+
108
+ useKeepAwake(); // screen stays on for as long as this component is mounted
109
+ </script>
110
+ <Text>Screen will not sleep</Text>
111
+ ```
112
+
113
+ ```tsx
114
+ // Solid
115
+ import { createKeepAwake } from '@symbiote-native/keep-awake/solid';
116
+
117
+ function KeepAwakeScreen() {
118
+ createKeepAwake(); // activates in the primitive body, releases via onCleanup on dispose
119
+
120
+ return <Text>Screen will not sleep</Text>;
121
+ }
122
+ ```
123
+
98
124
  ```ts
99
125
  // Angular — examples/expo-angular/src/screens/KeepAwakeScreen.ts
100
126
  import { Component, inject } from '@angular/core';
101
127
  import { KeepAwakeService } from '@symbiote-native/keep-awake/angular';
102
128
 
103
- @Component({ /* ... */ })
129
+ @Component({/* ... */})
104
130
  export class KeepAwakeScreen {
105
131
  constructor() {
106
132
  inject(KeepAwakeService).connect();
@@ -123,25 +149,31 @@ as a minimal `unknown` placeholder: upstream's own shape there is web-specific a
123
149
  analogue, and native listeners for it rarely fire.
124
150
 
125
151
  ```ts
126
- import { activateKeepAwakeAsync, deactivateKeepAwake } from '@symbiote-native/keep-awake';
152
+ import {
153
+ activateKeepAwakeAsync,
154
+ deactivateKeepAwake,
155
+ } from '@symbiote-native/keep-awake';
127
156
 
128
157
  // framework-scoped entry points re-export the same free functions, plus a lifecycle
129
158
  // hook/composable/service:
130
159
  import { useKeepAwake } from '@symbiote-native/keep-awake/react';
131
160
  import { useKeepAwake } from '@symbiote-native/keep-awake/vue';
161
+ import { useKeepAwake } from '@symbiote-native/keep-awake/svelte';
162
+ import { createKeepAwake } from '@symbiote-native/keep-awake/solid';
132
163
  import { KeepAwakeService } from '@symbiote-native/keep-awake/angular';
133
164
  ```
134
165
 
135
- Each hook/composable/service activates a lock on mount (optionally registering `options.listener`
136
- once activation resolves) and deactivates it on unmount — mirroring upstream's own
137
- `useKeepAwake(tag?, options?)`.
166
+ Each hook/composable/rune/primitive/service activates a lock on mount (optionally registering
167
+ `options.listener` once activation resolves) and deactivates it on unmount — mirroring upstream's
168
+ own `useKeepAwake(tag?, options?)`. Solid's `createKeepAwake(tag?, options?)` does it from the
169
+ primitive body, releasing through `onCleanup`.
138
170
 
139
171
  ## Test it
140
172
 
141
173
  No Fabric/Descriptor angle at all — keep-awake is a pure async-function + `EventEmitter` listener
142
174
  surface, never a view. Tests inject a fake native-module object in place of the real
143
175
  `requireNativeModule` resolution (`src/core/keep-awake.test.ts`,
144
- `src/{react,vue,angular}/**/*.test.{ts,tsx}`, `vitest`), the same pattern
176
+ `src/{react,vue,svelte,solid,angular}/**/*.test.{ts,tsx}`, `vitest`), the same pattern
145
177
  `@symbiote-native/battery` and `@symbiote-native/device` use — no `installFabric()`-driven Fabric
146
178
  assertions on the core level, only the adapter lifecycle tests mount through the fake Fabric slot
147
179
  to prove activate-on-mount/deactivate-on-unmount. Native rendering itself is verified on-device —
@@ -33,7 +33,7 @@ var __runInitializers = (this && this.__runInitializers) || function (thisArg, i
33
33
  return useValue ? value : void 0;
34
34
  };
35
35
  import { effect, inject, Injectable, Injector } from '@angular/core';
36
- import { activateKeepAwakeAsync, deactivateKeepAwake } from '../../../core/index.js';
36
+ import { activateKeepAwakeAsync, deactivateKeepAwake, } from '../../../core/index.js';
37
37
  import { createKeepAwakeListenerAttachment } from '../../../core/listener-attachment.js';
38
38
  // Angular twin of React's `useKeepAwake` hook and Vue's `useKeepAwake` composable. See
39
39
  // LowPowerModeService (packages/battery) for the `connect()`/`effect()` pattern rationale — same
@@ -1,3 +1,3 @@
1
1
  export { ExpoKeepAwakeTag, isAvailableAsync, activateKeepAwakeAsync, deactivateKeepAwake, addListener, } from './keep-awake';
2
- export type { KeepAwakeEvent, KeepAwakeListener, KeepAwakeOptions } from './types';
2
+ export type { KeepAwakeEvent, KeepAwakeListener, KeepAwakeOptions, } from './types';
3
3
  export type { EventSubscription } from 'expo-modules-core';
@@ -7,7 +7,7 @@
7
7
  // that's not reachable here (only core's public API is), so an UnavailabilityError from
8
8
  // `addListener` is just swallowed by the trailing `.catch(() => {})` instead - same net effect.
9
9
  import { useEffect, useId } from 'react';
10
- import { activateKeepAwakeAsync, deactivateKeepAwake } from '../../../core/index.js';
10
+ import { activateKeepAwakeAsync, deactivateKeepAwake, } from '../../../core/index.js';
11
11
  import { createKeepAwakeListenerAttachment } from '../../../core/listener-attachment.js';
12
12
  export function useKeepAwake(tag, options) {
13
13
  const defaultTag = useId();
@@ -0,0 +1,2 @@
1
+ export { createKeepAwake } from './primitives/create-keep-awake';
2
+ export * from '../core';
@@ -0,0 +1,6 @@
1
+ // @symbiote-native/keep-awake/solid: the Solid entry over the framework-agnostic core. The
2
+ // lifecycle bucket is `primitives/` and the name is `create*` (never `hooks/`/`use*`, that is
3
+ // React's term and Solid's word for consuming an existing thing) — see
4
+ // adapters/solid/src/primitives for the same convention.
5
+ export { createKeepAwake } from './primitives/create-keep-awake.js';
6
+ export * from '../core/index.js';
@@ -0,0 +1,2 @@
1
+ import { type KeepAwakeOptions } from '../../core';
2
+ export declare function createKeepAwake(tag?: string, options?: KeepAwakeOptions): void;
@@ -0,0 +1,41 @@
1
+ // Solid lifecycle wiring over the framework-agnostic core (core/keep-awake.ts): activates a
2
+ // keep-awake lock in the primitive body, deactivates it when the owner is disposed — the Solid
3
+ // twin of React's hook, Vue's composable, Svelte's rune and Angular's KeepAwakeService.connect().
4
+ //
5
+ // `primitives/` and `create*`, not `hooks/`/`use*`: Solid's ecosystem calls a composable reactive
6
+ // function a PRIMITIVE and reserves `use*` for consuming something that already exists. Full
7
+ // rationale in adapters/solid/src/primitives/create-color-scheme.ts's header.
8
+ //
9
+ // Activation runs SYNCHRONOUSLY in the body with `onCleanup` for teardown, not from a mount hook
10
+ // (React's useEffect, Vue's onMounted, Svelte's $effect) — the lock is requested one tick earlier,
11
+ // and nothing can interleave between construction and the request.
12
+ //
13
+ // Nothing reactive is returned: keeping the screen awake is a pure side effect for the owner's
14
+ // lifetime, so there is no accessor and the once-per-owner contract matches Vue/Svelte/Angular
15
+ // rather than React's hook, which re-runs when the tag changes.
16
+ //
17
+ // No `useId` in Solid, so the default tag comes from a module-local counter, as in Vue and Svelte.
18
+ //
19
+ // Outside a component / createRoot there is no owner for `onCleanup`, so the lock is never
20
+ // released — see create-color-scheme's header for the same documented caveat.
21
+ import { onCleanup } from 'solid-js';
22
+ import { activateKeepAwakeAsync, deactivateKeepAwake, } from '../../core/index.js';
23
+ import { createKeepAwakeListenerAttachment } from '../../core/listener-attachment.js';
24
+ let tagCounter = 0;
25
+ export function createKeepAwake(tag, options) {
26
+ const tagOrDefault = tag ?? `keep-awake-tag-${++tagCounter}`;
27
+ // One attachment per owner: the body runs once, so it spans the single activate/onCleanup pair.
28
+ const attachment = createKeepAwakeListenerAttachment(tagOrDefault, options?.listener);
29
+ activateKeepAwakeAsync(tagOrDefault)
30
+ .then(() => attachment.attach())
31
+ .catch(() => { });
32
+ onCleanup(() => {
33
+ attachment.release();
34
+ if (options?.suppressDeactivateWarnings) {
35
+ deactivateKeepAwake(tagOrDefault).catch(() => { });
36
+ }
37
+ else {
38
+ deactivateKeepAwake(tagOrDefault);
39
+ }
40
+ });
41
+ }
@@ -13,7 +13,7 @@
13
13
  //
14
14
  // No `useId` in Svelte, so the default tag comes from a module-local counter, as in Vue's
15
15
  // composable.
16
- import { activateKeepAwakeAsync, deactivateKeepAwake } from '../../core/index.js';
16
+ import { activateKeepAwakeAsync, deactivateKeepAwake, } from '../../core/index.js';
17
17
  import { createKeepAwakeListenerAttachment } from '../../core/listener-attachment.js';
18
18
  let tagCounter = 0;
19
19
  export function useKeepAwake(tag, options) {
@@ -4,7 +4,7 @@
4
4
  // counter instead — simplest robust way to give each composable instance its own tag when the
5
5
  // caller doesn't supply one.
6
6
  import { onMounted, onUnmounted } from '@vue/runtime-core';
7
- import { activateKeepAwakeAsync, deactivateKeepAwake } from '../../../core/index.js';
7
+ import { activateKeepAwakeAsync, deactivateKeepAwake, } from '../../../core/index.js';
8
8
  import { createKeepAwakeListenerAttachment } from '../../../core/listener-attachment.js';
9
9
  let tagCounter = 0;
10
10
  export function useKeepAwake(tag, options) {
@@ -1,5 +1,5 @@
1
1
  import { effect, inject, Injectable, Injector } from '@angular/core';
2
- import { activateKeepAwakeAsync, deactivateKeepAwake } from '../../../core';
2
+ import { activateKeepAwakeAsync, deactivateKeepAwake, } from '../../../core';
3
3
  import { createKeepAwakeListenerAttachment } from '../../../core/listener-attachment';
4
4
  import * as i0 from "@angular/core";
5
5
  // Angular twin of React's `useKeepAwake` hook and Vue's `useKeepAwake` composable. See
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../src/angular/services/keep-awake.service/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,UAAU,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AACrE,OAAO,EAAE,sBAAsB,EAAE,mBAAmB,EAAyB,MAAM,eAAe,CAAC;AACnG,OAAO,EAAE,iCAAiC,EAAE,MAAM,mCAAmC,CAAC;;AAEtF,uFAAuF;AACvF,iGAAiG;AACjG,+FAA+F;AAC/F,6FAA6F;AAC7F,yFAAyF;AACzF,EAAE;AACF,0DAA0D;AAC1D,IAAI,UAAU,GAAG,CAAC,CAAC;AAGnB,MAAM,OAAO,gBAAgB;IACV,QAAQ,GAAG,MAAM,CAAC,QAAQ,CAAC,CAAC;IAE7C,OAAO,CAAC,GAAY,EAAE,OAA0B;QAC9C,MAAM,YAAY,GAAG,GAAG,IAAI,kBAAkB,EAAE,UAAU,EAAE,CAAC;QAE7D,MAAM,CACJ,SAAS,CAAC,EAAE;YACV,sFAAsF;YACtF,2DAA2D;YAC3D,MAAM,UAAU,GAAG,iCAAiC,CAAC,YAAY,EAAE,OAAO,EAAE,QAAQ,CAAC,CAAC;YAEtF,sBAAsB,CAAC,YAAY,CAAC;iBACjC,IAAI,CAAC,GAAG,EAAE,CAAC,UAAU,CAAC,MAAM,EAAE,CAAC;iBAC/B,KAAK,CAAC,GAAG,EAAE,GAAE,CAAC,CAAC,CAAC;YAEnB,SAAS,CAAC,GAAG,EAAE;gBACb,UAAU,CAAC,OAAO,EAAE,CAAC;gBACrB,IAAI,OAAO,EAAE,0BAA0B,EAAE,CAAC;oBACxC,mBAAmB,CAAC,YAAY,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE,GAAE,CAAC,CAAC,CAAC;gBACpD,CAAC;qBAAM,CAAC;oBACN,mBAAmB,CAAC,YAAY,CAAC,CAAC;gBACpC,CAAC;YACH,CAAC,CAAC,CAAC;QACL,CAAC,EACD,EAAE,QAAQ,EAAE,IAAI,CAAC,QAAQ,EAAE,CAC5B,CAAC;IACJ,CAAC;uGA3BU,gBAAgB;2GAAhB,gBAAgB,cADH,MAAM;;2FACnB,gBAAgB;kBAD5B,UAAU;mBAAC,EAAE,UAAU,EAAE,MAAM,EAAE"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../src/angular/services/keep-awake.service/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,UAAU,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AACrE,OAAO,EACL,sBAAsB,EACtB,mBAAmB,GAEpB,MAAM,eAAe,CAAC;AACvB,OAAO,EAAE,iCAAiC,EAAE,MAAM,mCAAmC,CAAC;;AAEtF,uFAAuF;AACvF,iGAAiG;AACjG,+FAA+F;AAC/F,6FAA6F;AAC7F,yFAAyF;AACzF,EAAE;AACF,0DAA0D;AAC1D,IAAI,UAAU,GAAG,CAAC,CAAC;AAGnB,MAAM,OAAO,gBAAgB;IACV,QAAQ,GAAG,MAAM,CAAC,QAAQ,CAAC,CAAC;IAE7C,OAAO,CAAC,GAAY,EAAE,OAA0B;QAC9C,MAAM,YAAY,GAAG,GAAG,IAAI,kBAAkB,EAAE,UAAU,EAAE,CAAC;QAE7D,MAAM,CACJ,SAAS,CAAC,EAAE;YACV,sFAAsF;YACtF,2DAA2D;YAC3D,MAAM,UAAU,GAAG,iCAAiC,CAClD,YAAY,EACZ,OAAO,EAAE,QAAQ,CAClB,CAAC;YAEF,sBAAsB,CAAC,YAAY,CAAC;iBACjC,IAAI,CAAC,GAAG,EAAE,CAAC,UAAU,CAAC,MAAM,EAAE,CAAC;iBAC/B,KAAK,CAAC,GAAG,EAAE,GAAE,CAAC,CAAC,CAAC;YAEnB,SAAS,CAAC,GAAG,EAAE;gBACb,UAAU,CAAC,OAAO,EAAE,CAAC;gBACrB,IAAI,OAAO,EAAE,0BAA0B,EAAE,CAAC;oBACxC,mBAAmB,CAAC,YAAY,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE,GAAE,CAAC,CAAC,CAAC;gBACpD,CAAC;qBAAM,CAAC;oBACN,mBAAmB,CAAC,YAAY,CAAC,CAAC;gBACpC,CAAC;YACH,CAAC,CAAC,CAAC;QACL,CAAC,EACD,EAAE,QAAQ,EAAE,IAAI,CAAC,QAAQ,EAAE,CAC5B,CAAC;IACJ,CAAC;uGA9BU,gBAAgB;2GAAhB,gBAAgB,cADH,MAAM;;2FACnB,gBAAgB;kBAD5B,UAAU;mBAAC,EAAE,UAAU,EAAE,MAAM,EAAE"}
@@ -1,3 +1,3 @@
1
1
  export { ExpoKeepAwakeTag, isAvailableAsync, activateKeepAwakeAsync, deactivateKeepAwake, addListener, } from './keep-awake';
2
- export type { KeepAwakeEvent, KeepAwakeListener, KeepAwakeOptions } from './types';
2
+ export type { KeepAwakeEvent, KeepAwakeListener, KeepAwakeOptions, } from './types';
3
3
  export type { EventSubscription } from 'expo-modules-core';
@@ -1 +1 @@
1
- {"version":3,"file":"keep-awake.js","sourceRoot":"","sources":["../../src/core/keep-awake.ts"],"names":[],"mappings":"AAAA,0FAA0F;AAC1F,oFAAoF;AACpF,2FAA2F;AAC3F,6EAA6E;AAC7E,qFAAqF;AACrF,OAAO,EAAE,mBAAmB,EAA0B,MAAM,mBAAmB,CAAC;AAChF,OAAO,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAGhD,MAAM,CAAC,MAAM,gBAAgB,GAAG,yBAAyB,CAAC;AAE1D,4EAA4E;AAC5E,MAAM,CAAC,KAAK,UAAU,gBAAgB;IACpC,IAAI,aAAa,CAAC,gBAAgB,EAAE,CAAC;QACnC,OAAO,MAAM,aAAa,CAAC,gBAAgB,EAAE,CAAC;IAChD,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC;AAED;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,sBAAsB,CAAC,MAAc,gBAAgB;IACzE,MAAM,aAAa,CAAC,QAAQ,EAAE,CAAC,GAAG,CAAC,CAAC;AACtC,CAAC;AAED,iGAAiG;AACjG,MAAM,CAAC,KAAK,UAAU,mBAAmB,CAAC,MAAc,gBAAgB;IACtE,MAAM,aAAa,CAAC,UAAU,EAAE,CAAC,GAAG,CAAC,CAAC;AACxC,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,WAAW,CACzB,aAAyC,EACzC,QAA4B;IAE5B,IAAI,CAAC,aAAa,CAAC,iBAAiB,EAAE,CAAC;QACrC,MAAM,IAAI,mBAAmB,CAAC,eAAe,EAAE,mBAAmB,CAAC,CAAC;IACtE,CAAC;IACD,MAAM,GAAG,GAAG,OAAO,aAAa,KAAK,QAAQ,CAAC,CAAC,CAAC,aAAa,CAAC,CAAC,CAAC,gBAAgB,CAAC;IACjF,MAAM,gBAAgB,GAAG,OAAO,aAAa,KAAK,UAAU,CAAC,CAAC,CAAC,aAAa,CAAC,CAAC,CAAC,QAAQ,CAAC;IACxF,IAAI,CAAC,gBAAgB,EAAE,CAAC;QACtB,MAAM,IAAI,SAAS,CAAC,0CAA0C,CAAC,CAAC;IAClE,CAAC;IACD,OAAO,aAAa,CAAC,iBAAiB,CAAC,GAAG,EAAE,gBAAgB,CAAC,CAAC;AAChE,CAAC"}
1
+ {"version":3,"file":"keep-awake.js","sourceRoot":"","sources":["../../src/core/keep-awake.ts"],"names":[],"mappings":"AAAA,0FAA0F;AAC1F,oFAAoF;AACpF,2FAA2F;AAC3F,6EAA6E;AAC7E,qFAAqF;AACrF,OAAO,EAAE,mBAAmB,EAA0B,MAAM,mBAAmB,CAAC;AAChF,OAAO,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAGhD,MAAM,CAAC,MAAM,gBAAgB,GAAG,yBAAyB,CAAC;AAE1D,4EAA4E;AAC5E,MAAM,CAAC,KAAK,UAAU,gBAAgB;IACpC,IAAI,aAAa,CAAC,gBAAgB,EAAE,CAAC;QACnC,OAAO,MAAM,aAAa,CAAC,gBAAgB,EAAE,CAAC;IAChD,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC;AAED;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,sBAAsB,CAC1C,MAAc,gBAAgB;IAE9B,MAAM,aAAa,CAAC,QAAQ,EAAE,CAAC,GAAG,CAAC,CAAC;AACtC,CAAC;AAED,iGAAiG;AACjG,MAAM,CAAC,KAAK,UAAU,mBAAmB,CACvC,MAAc,gBAAgB;IAE9B,MAAM,aAAa,CAAC,UAAU,EAAE,CAAC,GAAG,CAAC,CAAC;AACxC,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,WAAW,CACzB,aAAyC,EACzC,QAA4B;IAE5B,IAAI,CAAC,aAAa,CAAC,iBAAiB,EAAE,CAAC;QACrC,MAAM,IAAI,mBAAmB,CAAC,eAAe,EAAE,mBAAmB,CAAC,CAAC;IACtE,CAAC;IACD,MAAM,GAAG,GACP,OAAO,aAAa,KAAK,QAAQ,CAAC,CAAC,CAAC,aAAa,CAAC,CAAC,CAAC,gBAAgB,CAAC;IACvE,MAAM,gBAAgB,GACpB,OAAO,aAAa,KAAK,UAAU,CAAC,CAAC,CAAC,aAAa,CAAC,CAAC,CAAC,QAAQ,CAAC;IACjE,IAAI,CAAC,gBAAgB,EAAE,CAAC;QACtB,MAAM,IAAI,SAAS,CAAC,0CAA0C,CAAC,CAAC;IAClE,CAAC;IACD,OAAO,aAAa,CAAC,iBAAiB,CAAC,GAAG,EAAE,gBAAgB,CAAC,CAAC;AAChE,CAAC"}
@@ -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;AAIxD,MAAM,2BAA2B,GAAG,eAAe,CAAC;AAapD,MAAM,CAAC,MAAM,aAAa,GAAG,mBAAmB,CAC9C,2BAA2B,CAC5B,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;AAIxD,MAAM,2BAA2B,GAAG,eAAe,CAAC;AAgBpD,MAAM,CAAC,MAAM,aAAa,GAAG,mBAAmB,CAC9C,2BAA2B,CAC5B,CAAC"}
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@symbiote-native/keep-awake",
3
- "version": "0.2.0",
4
- "description": "expo-keep-awake wrapped for SymbioteNative — one framework-agnostic core, built once and reachable from the React, Vue, and Angular adapters. Keeps the screen awake for the lifetime of a mounted component/composable/service, with an optional listener for keep-awake state changes.",
3
+ "version": "1.0.0",
4
+ "description": "expo-keep-awake wrapped for SymbioteNative — one framework-agnostic core, built once and reachable from the React, Vue, Svelte, Solid, and Angular adapters. Keeps the screen awake for the lifetime of a mounted component/composable/service, with an optional listener for keep-awake state changes.",
5
5
  "license": "MIT",
6
6
  "repository": {
7
7
  "type": "git",
@@ -13,6 +13,18 @@
13
13
  "url": "https://github.com/OneEyed1366/symbiote-native/issues"
14
14
  },
15
15
  "author": "Andrey Prokopenko <psevdoproger@gmail.com>",
16
+ "keywords": [
17
+ "react-native",
18
+ "symbiote-native",
19
+ "expo-keep-awake",
20
+ "react",
21
+ "vue",
22
+ "svelte",
23
+ "solid",
24
+ "angular",
25
+ "wake-lock",
26
+ "screen-on"
27
+ ],
16
28
  "type": "module",
17
29
  "main": "./build/core/index.js",
18
30
  "module": "./build/core/index.js",
@@ -34,6 +46,10 @@
34
46
  "types": "./build/svelte/index.d.ts",
35
47
  "default": "./build/svelte/index.js"
36
48
  },
49
+ "./solid": {
50
+ "types": "./build/solid/index.d.ts",
51
+ "default": "./build/solid/index.js"
52
+ },
37
53
  "./angular": {
38
54
  "types": "./build-ngc/angular/index.d.ts",
39
55
  "react-native": "./build-ngc/angular/index.js",
@@ -57,17 +73,19 @@
57
73
  "expo-modules-core": "57.0.5"
58
74
  },
59
75
  "peerDependencies": {
60
- "@symbiote-native/angular": ">=0.6.2",
61
- "@symbiote-native/engine": ">=0.1.7",
62
- "@symbiote-native/react": ">=0.2.8",
63
- "@symbiote-native/svelte": ">=0.1.0",
64
- "@symbiote-native/vue": ">=0.3.8",
65
76
  "@angular/core": ">=20",
66
77
  "@vue/runtime-core": "^3.5.13",
67
78
  "react": ">=19.0.0",
68
79
  "react-native": ">=0.86",
80
+ "solid-js": ">=1.9.0",
69
81
  "svelte": ">=5.56.0",
70
- "vue": ">=3.5.0"
82
+ "vue": ">=3.5.0",
83
+ "@symbiote-native/angular": "^1.0.0",
84
+ "@symbiote-native/engine": "^0.4.0",
85
+ "@symbiote-native/react": "^1.0.0",
86
+ "@symbiote-native/solid": "^1.0.0",
87
+ "@symbiote-native/svelte": "^1.0.0",
88
+ "@symbiote-native/vue": "^1.0.0"
71
89
  },
72
90
  "peerDependenciesMeta": {
73
91
  "@symbiote-native/angular": {
@@ -76,6 +94,9 @@
76
94
  "@symbiote-native/react": {
77
95
  "optional": true
78
96
  },
97
+ "@symbiote-native/solid": {
98
+ "optional": true
99
+ },
79
100
  "@symbiote-native/svelte": {
80
101
  "optional": true
81
102
  },
@@ -91,6 +112,9 @@
91
112
  "react": {
92
113
  "optional": true
93
114
  },
115
+ "solid-js": {
116
+ "optional": true
117
+ },
94
118
  "svelte": {
95
119
  "optional": true
96
120
  },
@@ -106,14 +130,16 @@
106
130
  "@types/react": "^19.2.0",
107
131
  "@vue/runtime-core": "^3.5.13",
108
132
  "react": "19.2.3",
133
+ "solid-js": "^1.9.14",
109
134
  "svelte": "^5.56.0",
110
135
  "typescript": "~6.0.0",
111
- "@symbiote-native/angular": "0.7.0",
112
- "@symbiote-native/engine": "0.2.0",
113
- "@symbiote-native/react": "0.3.0",
114
- "@symbiote-native/svelte": "0.2.0",
115
- "@symbiote-native/test-utils": "0.1.6",
116
- "@symbiote-native/vue": "0.4.0"
136
+ "@symbiote-native/angular": "1.0.0",
137
+ "@symbiote-native/engine": "0.4.0",
138
+ "@symbiote-native/react": "1.0.0",
139
+ "@symbiote-native/solid": "1.0.0",
140
+ "@symbiote-native/svelte": "1.0.0",
141
+ "@symbiote-native/test-utils": "0.3.0",
142
+ "@symbiote-native/vue": "1.0.0"
117
143
  },
118
144
  "scripts": {
119
145
  "typecheck": "tsc --build",
@@ -1,5 +1,9 @@
1
1
  import { effect, inject, Injectable, Injector } from '@angular/core';
2
- import { activateKeepAwakeAsync, deactivateKeepAwake, type KeepAwakeOptions } from '../../../core';
2
+ import {
3
+ activateKeepAwakeAsync,
4
+ deactivateKeepAwake,
5
+ type KeepAwakeOptions,
6
+ } from '../../../core';
3
7
  import { createKeepAwakeListenerAttachment } from '../../../core/listener-attachment';
4
8
 
5
9
  // Angular twin of React's `useKeepAwake` hook and Vue's `useKeepAwake` composable. See
@@ -22,7 +26,10 @@ export class KeepAwakeService {
22
26
  onCleanup => {
23
27
  // Per effect run: onCleanup releases this exact attachment, so a re-run always starts
24
28
  // from a fresh one rather than reviving a released attach.
25
- const attachment = createKeepAwakeListenerAttachment(tagOrDefault, options?.listener);
29
+ const attachment = createKeepAwakeListenerAttachment(
30
+ tagOrDefault,
31
+ options?.listener,
32
+ );
26
33
 
27
34
  activateKeepAwakeAsync(tagOrDefault)
28
35
  .then(() => attachment.attach())
package/src/core/index.ts CHANGED
@@ -5,5 +5,9 @@ export {
5
5
  deactivateKeepAwake,
6
6
  addListener,
7
7
  } from './keep-awake';
8
- export type { KeepAwakeEvent, KeepAwakeListener, KeepAwakeOptions } from './types';
8
+ export type {
9
+ KeepAwakeEvent,
10
+ KeepAwakeListener,
11
+ KeepAwakeOptions,
12
+ } from './types';
9
13
  export type { EventSubscription } from 'expo-modules-core';
@@ -21,12 +21,16 @@ export async function isAvailableAsync(): Promise<boolean> {
21
21
  * Activates a keep-awake lock under `tag` (the shared default tag when none is given) — the
22
22
  * screen stays on for as long as any tag holds an active lock.
23
23
  */
24
- export async function activateKeepAwakeAsync(tag: string = ExpoKeepAwakeTag): Promise<void> {
24
+ export async function activateKeepAwakeAsync(
25
+ tag: string = ExpoKeepAwakeTag,
26
+ ): Promise<void> {
25
27
  await expoKeepAwake.activate?.(tag);
26
28
  }
27
29
 
28
30
  /** Releases the keep-awake lock held under `tag` (the shared default tag when none is given). */
29
- export async function deactivateKeepAwake(tag: string = ExpoKeepAwakeTag): Promise<void> {
31
+ export async function deactivateKeepAwake(
32
+ tag: string = ExpoKeepAwakeTag,
33
+ ): Promise<void> {
30
34
  await expoKeepAwake.deactivate?.(tag);
31
35
  }
32
36
 
@@ -41,8 +45,10 @@ export function addListener(
41
45
  if (!expoKeepAwake.addListenerForTag) {
42
46
  throw new UnavailabilityError('ExpoKeepAwake', 'addListenerForTag');
43
47
  }
44
- const tag = typeof tagOrListener === 'string' ? tagOrListener : ExpoKeepAwakeTag;
45
- const resolvedListener = typeof tagOrListener === 'function' ? tagOrListener : listener;
48
+ const tag =
49
+ typeof tagOrListener === 'string' ? tagOrListener : ExpoKeepAwakeTag;
50
+ const resolvedListener =
51
+ typeof tagOrListener === 'function' ? tagOrListener : listener;
46
52
  if (!resolvedListener) {
47
53
  throw new TypeError('addListener requires a listener function');
48
54
  }
@@ -12,7 +12,10 @@ export type INativeKeepAwakeModule = {
12
12
  isAvailableAsync?(): Promise<boolean>;
13
13
  activate?(tag: string): Promise<void>;
14
14
  deactivate?(tag: string): Promise<void>;
15
- addListenerForTag?(tag: string, listener: KeepAwakeListener): EventSubscription;
15
+ addListenerForTag?(
16
+ tag: string,
17
+ listener: KeepAwakeListener,
18
+ ): EventSubscription;
16
19
  };
17
20
 
18
21
  export const expoKeepAwake = requireNativeModule<INativeKeepAwakeModule>(
@@ -7,7 +7,11 @@
7
7
  // that's not reachable here (only core's public API is), so an UnavailabilityError from
8
8
  // `addListener` is just swallowed by the trailing `.catch(() => {})` instead - same net effect.
9
9
  import { useEffect, useId } from 'react';
10
- import { activateKeepAwakeAsync, deactivateKeepAwake, type KeepAwakeOptions } from '../../../core';
10
+ import {
11
+ activateKeepAwakeAsync,
12
+ deactivateKeepAwake,
13
+ type KeepAwakeOptions,
14
+ } from '../../../core';
11
15
  import { createKeepAwakeListenerAttachment } from '../../../core/listener-attachment';
12
16
 
13
17
  export function useKeepAwake(tag?: string, options?: KeepAwakeOptions): void {
@@ -17,7 +21,10 @@ export function useKeepAwake(tag?: string, options?: KeepAwakeOptions): void {
17
21
  useEffect(() => {
18
22
  // Per effect run, not per hook call - a changed tag tears the old attachment down with the
19
23
  // rest of the cleanup and starts a fresh one.
20
- const attachment = createKeepAwakeListenerAttachment(tagOrDefault, options?.listener);
24
+ const attachment = createKeepAwakeListenerAttachment(
25
+ tagOrDefault,
26
+ options?.listener,
27
+ );
21
28
 
22
29
  activateKeepAwakeAsync(tagOrDefault)
23
30
  .then(() => attachment.attach())
@@ -0,0 +1,7 @@
1
+ // @symbiote-native/keep-awake/solid: the Solid entry over the framework-agnostic core. The
2
+ // lifecycle bucket is `primitives/` and the name is `create*` (never `hooks/`/`use*`, that is
3
+ // React's term and Solid's word for consuming an existing thing) — see
4
+ // adapters/solid/src/primitives for the same convention.
5
+
6
+ export { createKeepAwake } from './primitives/create-keep-awake';
7
+ export * from '../core';
@@ -0,0 +1,54 @@
1
+ // Solid lifecycle wiring over the framework-agnostic core (core/keep-awake.ts): activates a
2
+ // keep-awake lock in the primitive body, deactivates it when the owner is disposed — the Solid
3
+ // twin of React's hook, Vue's composable, Svelte's rune and Angular's KeepAwakeService.connect().
4
+ //
5
+ // `primitives/` and `create*`, not `hooks/`/`use*`: Solid's ecosystem calls a composable reactive
6
+ // function a PRIMITIVE and reserves `use*` for consuming something that already exists. Full
7
+ // rationale in adapters/solid/src/primitives/create-color-scheme.ts's header.
8
+ //
9
+ // Activation runs SYNCHRONOUSLY in the body with `onCleanup` for teardown, not from a mount hook
10
+ // (React's useEffect, Vue's onMounted, Svelte's $effect) — the lock is requested one tick earlier,
11
+ // and nothing can interleave between construction and the request.
12
+ //
13
+ // Nothing reactive is returned: keeping the screen awake is a pure side effect for the owner's
14
+ // lifetime, so there is no accessor and the once-per-owner contract matches Vue/Svelte/Angular
15
+ // rather than React's hook, which re-runs when the tag changes.
16
+ //
17
+ // No `useId` in Solid, so the default tag comes from a module-local counter, as in Vue and Svelte.
18
+ //
19
+ // Outside a component / createRoot there is no owner for `onCleanup`, so the lock is never
20
+ // released — see create-color-scheme's header for the same documented caveat.
21
+ import { onCleanup } from 'solid-js';
22
+ import {
23
+ activateKeepAwakeAsync,
24
+ deactivateKeepAwake,
25
+ type KeepAwakeOptions,
26
+ } from '../../core';
27
+ import { createKeepAwakeListenerAttachment } from '../../core/listener-attachment';
28
+
29
+ let tagCounter = 0;
30
+
31
+ export function createKeepAwake(
32
+ tag?: string,
33
+ options?: KeepAwakeOptions,
34
+ ): void {
35
+ const tagOrDefault = tag ?? `keep-awake-tag-${++tagCounter}`;
36
+ // One attachment per owner: the body runs once, so it spans the single activate/onCleanup pair.
37
+ const attachment = createKeepAwakeListenerAttachment(
38
+ tagOrDefault,
39
+ options?.listener,
40
+ );
41
+
42
+ activateKeepAwakeAsync(tagOrDefault)
43
+ .then(() => attachment.attach())
44
+ .catch(() => {});
45
+
46
+ onCleanup(() => {
47
+ attachment.release();
48
+ if (options?.suppressDeactivateWarnings) {
49
+ deactivateKeepAwake(tagOrDefault).catch(() => {});
50
+ } else {
51
+ deactivateKeepAwake(tagOrDefault);
52
+ }
53
+ });
54
+ }
@@ -13,7 +13,11 @@
13
13
  //
14
14
  // No `useId` in Svelte, so the default tag comes from a module-local counter, as in Vue's
15
15
  // composable.
16
- import { activateKeepAwakeAsync, deactivateKeepAwake, type KeepAwakeOptions } from '../../core';
16
+ import {
17
+ activateKeepAwakeAsync,
18
+ deactivateKeepAwake,
19
+ type KeepAwakeOptions,
20
+ } from '../../core';
17
21
  import { createKeepAwakeListenerAttachment } from '../../core/listener-attachment';
18
22
 
19
23
  let tagCounter = 0;
@@ -23,7 +27,10 @@ export function useKeepAwake(tag?: string, options?: KeepAwakeOptions): void {
23
27
 
24
28
  $effect(() => {
25
29
  // Inside the effect, so the attachment shares the teardown returned below.
26
- const attachment = createKeepAwakeListenerAttachment(tagOrDefault, options?.listener);
30
+ const attachment = createKeepAwakeListenerAttachment(
31
+ tagOrDefault,
32
+ options?.listener,
33
+ );
27
34
 
28
35
  activateKeepAwakeAsync(tagOrDefault)
29
36
  .then(() => attachment.attach())
@@ -4,7 +4,11 @@
4
4
  // counter instead — simplest robust way to give each composable instance its own tag when the
5
5
  // caller doesn't supply one.
6
6
  import { onMounted, onUnmounted } from '@vue/runtime-core';
7
- import { activateKeepAwakeAsync, deactivateKeepAwake, type KeepAwakeOptions } from '../../../core';
7
+ import {
8
+ activateKeepAwakeAsync,
9
+ deactivateKeepAwake,
10
+ type KeepAwakeOptions,
11
+ } from '../../../core';
8
12
  import { createKeepAwakeListenerAttachment } from '../../../core/listener-attachment';
9
13
 
10
14
  let tagCounter = 0;
@@ -13,7 +17,10 @@ export function useKeepAwake(tag?: string, options?: KeepAwakeOptions): void {
13
17
  const tagOrDefault = tag ?? `keep-awake-tag-${++tagCounter}`;
14
18
  // Setup body scope: it runs once per instance, so one attachment spans the single
15
19
  // onMounted/onUnmounted pair - no need to re-create it on the mount hook.
16
- const attachment = createKeepAwakeListenerAttachment(tagOrDefault, options?.listener);
20
+ const attachment = createKeepAwakeListenerAttachment(
21
+ tagOrDefault,
22
+ options?.listener,
23
+ );
17
24
 
18
25
  onMounted(() => {
19
26
  activateKeepAwakeAsync(tagOrDefault)