@signality/core 0.0.1-alpha.3 → 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +51 -47
- package/browser/index.d.ts +0 -1
- package/fesm2022/signality-core-browser-speech-recognition.mjs +1 -1
- package/fesm2022/signality-core-browser-speech-recognition.mjs.map +1 -1
- package/fesm2022/signality-core-browser.mjs +0 -1
- package/fesm2022/signality-core-browser.mjs.map +1 -1
- package/fesm2022/signality-core-scheduling-interval.mjs +3 -1
- package/fesm2022/signality-core-scheduling-interval.mjs.map +1 -1
- package/package.json +6 -10
- package/browser/wake-lock/index.d.ts +0 -76
- package/fesm2022/signality-core-browser-wake-lock.mjs +0 -166
- package/fesm2022/signality-core-browser-wake-lock.mjs.map +0 -1
package/README.md
CHANGED
|
@@ -1,58 +1,62 @@
|
|
|
1
1
|
# @signality/core
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
A collection of atomic utilities for building reactive compositions in [Angular](https://angular.dev).
|
|
4
|
+
|
|
5
|
+
## Key Benefits
|
|
6
|
+
|
|
7
|
+
- **Signal-first design** — built on top of Angular [Signals](https://angular.dev/guide/signals), abstracting away from RxJS
|
|
8
|
+
- **Automatic cleanup** — utilities manage resource lifecycles automatically
|
|
9
|
+
- **SSR-compatible** — browser APIs are guarded with safe defaults on the server
|
|
10
|
+
- **Reactive inputs** — seamlessly handles static and reactive values
|
|
11
|
+
- **Tree-Shakable** — only the code you use ends up in your bundle
|
|
12
|
+
|
|
13
|
+
## Quick Example
|
|
14
|
+
|
|
15
|
+
```ts
|
|
16
|
+
import { Component, effect } from '@angular/core';
|
|
17
|
+
import { storage, speechSynthesis, favicon } from '@signality/core';
|
|
18
|
+
|
|
19
|
+
@Component({
|
|
20
|
+
template: `
|
|
21
|
+
<input [(ngModel)]="value" />
|
|
22
|
+
<button (click)="synthesis.speak(value())">Speak</button>
|
|
23
|
+
`,
|
|
24
|
+
})
|
|
25
|
+
export class Demo {
|
|
26
|
+
readonly value = storage('key', ''); // Web Storage API
|
|
27
|
+
readonly synthesis = speechSynthesis(); // Web Speech API
|
|
28
|
+
readonly fav = favicon(); // Dynamic Favicon
|
|
29
|
+
|
|
30
|
+
constructor() {
|
|
31
|
+
effect(() => {
|
|
32
|
+
if (this.synthesis.isSpeaking()) {
|
|
33
|
+
this.fav.setEmoji('🔊');
|
|
34
|
+
} else {
|
|
35
|
+
this.fav.reset();
|
|
36
|
+
}
|
|
37
|
+
});
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
## Framework Compatibility
|
|
43
|
+
|
|
44
|
+
| Tool | Minimum Version |
|
|
45
|
+
|-------------|-----------------|
|
|
46
|
+
| **Angular** | `v20.0.0` |
|
|
4
47
|
|
|
5
48
|
## Installation
|
|
6
49
|
|
|
7
50
|
```bash
|
|
8
|
-
|
|
51
|
+
pnpm add @signality/core
|
|
9
52
|
```
|
|
10
53
|
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
- **`pageVisibility()`** — Reactive page visibility state
|
|
18
|
-
- **`storage()`** — Reactive localStorage/sessionStorage with sync
|
|
19
|
-
- **`network()`** — Reactive network connection status
|
|
20
|
-
- **`fullscreen()`** — Reactive fullscreen API
|
|
21
|
-
- And [many more...](https://signality.dev/browser/battery)
|
|
22
|
-
|
|
23
|
-
### Element Utilities
|
|
24
|
-
- **`elementSize()`** — Reactive element dimensions
|
|
25
|
-
- **`elementVisibility()`** — Reactive Intersection Observer
|
|
26
|
-
- **`dropzone()`** — Reactive drag & drop zone
|
|
27
|
-
- **`windowSize()`** — Reactive window dimensions
|
|
28
|
-
- **`scrollPosition()`** — Reactive scroll position
|
|
29
|
-
- And [many more...](https://signality.dev/elements/active-element)
|
|
30
|
-
|
|
31
|
-
### Utils
|
|
32
|
-
- **`debounced()`** — Debounced writable signal
|
|
33
|
-
- **`throttled()`** — Throttled writable signal
|
|
34
|
-
|
|
35
|
-
## Usage
|
|
36
|
-
|
|
37
|
-
```typescript
|
|
38
|
-
import { battery, clipboard, elementSize, debounced } from '@signality/core';
|
|
39
|
-
|
|
40
|
-
// Battery status
|
|
41
|
-
const batteryStatus = battery();
|
|
42
|
-
// batteryStatus.level(), batteryStatus.charging()
|
|
43
|
-
|
|
44
|
-
// Clipboard operations
|
|
45
|
-
const clipboard = clipboard();
|
|
46
|
-
await clipboard.copy('Hello');
|
|
47
|
-
const text = await clipboard.paste();
|
|
48
|
-
|
|
49
|
-
// Element size tracking
|
|
50
|
-
const element = viewChild<ElementRef<HTMLDivElement>>('myElement');
|
|
51
|
-
const size = elementSize(element);
|
|
52
|
-
// size.width(), size.height()
|
|
53
|
-
|
|
54
|
-
// Debounced signal
|
|
55
|
-
const searchQuery = debounced('', 300);
|
|
54
|
+
Or with npm/yarn:
|
|
55
|
+
|
|
56
|
+
```bash
|
|
57
|
+
npm install @signality/core
|
|
58
|
+
# or
|
|
59
|
+
yarn add @signality/core
|
|
56
60
|
```
|
|
57
61
|
|
|
58
62
|
## Documentation
|
package/browser/index.d.ts
CHANGED
|
@@ -28,7 +28,6 @@ export * from '@signality/core/browser/storage';
|
|
|
28
28
|
export * from '@signality/core/browser/text-direction';
|
|
29
29
|
export * from '@signality/core/browser/text-selection';
|
|
30
30
|
export * from '@signality/core/browser/vibration';
|
|
31
|
-
export * from '@signality/core/browser/wake-lock';
|
|
32
31
|
export * from '@signality/core/browser/web-notification';
|
|
33
32
|
export * from '@signality/core/browser/web-share';
|
|
34
33
|
export * from '@signality/core/browser/web-worker';
|
|
@@ -39,7 +39,7 @@ import { permissionState } from '@signality/core/browser/permission-state';
|
|
|
39
39
|
*/
|
|
40
40
|
function speechRecognition(options) {
|
|
41
41
|
const { runInContext } = setupContext(options?.injector, speechRecognition);
|
|
42
|
-
return runInContext(({ isBrowser,
|
|
42
|
+
return runInContext(({ isBrowser, onCleanup }) => {
|
|
43
43
|
const isSupported = constSignal(isBrowser && ('SpeechRecognition' in window || 'webkitSpeechRecognition' in window));
|
|
44
44
|
if (!isSupported()) {
|
|
45
45
|
return {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"signality-core-browser-speech-recognition.mjs","sources":["../../../projects/core/browser/speech-recognition/index.ts","../../../projects/core/browser/speech-recognition/signality-core-browser-speech-recognition.ts"],"sourcesContent":["import { isSignal, type Signal, signal, untracked } from '@angular/core';\nimport { constSignal, NOOP_FN, setupContext, toValue } from '@signality/core/internal';\nimport type { MaybeSignal, WithInjector } from '@signality/core/types';\nimport { watcher } from '@signality/core/reactivity/watcher';\nimport { permissionState } from '@signality/core/browser/permission-state';\n\nexport interface SpeechRecognitionOptions extends WithInjector {\n /**\n * BCP 47 language tag for recognition (e.g. `'en-US'`).\n *\n * @default 'en-US'\n * @see [SpeechRecognition: lang on MDN](https://developer.mozilla.org/en-US/docs/Web/API/SpeechRecognition/lang)\n */\n readonly lang?: MaybeSignal<string>;\n\n /**\n * Whether to return interim (in-progress) results alongside final ones.\n *\n * @default false\n * @see [SpeechRecognition: interimResults on MDN](https://developer.mozilla.org/en-US/docs/Web/API/SpeechRecognition/interimResults)\n */\n readonly interimResults?: boolean;\n\n /**\n * Whether recognition continues after the user stops speaking.\n *\n * @default false\n * @see [SpeechRecognition: continuous on MDN](https://developer.mozilla.org/en-US/docs/Web/API/SpeechRecognition/continuous)\n */\n readonly continuous?: boolean;\n\n /**\n * Maximum number of alternative recognition results per utterance.\n *\n * @default 1\n * @see [SpeechRecognition: maxAlternatives on MDN](https://developer.mozilla.org/en-US/docs/Web/API/SpeechRecognition/maxAlternatives)\n */\n readonly maxAlternatives?: number;\n}\n\nexport interface SpeechRecognitionRef {\n /**\n * Whether the Speech Recognition API is supported in the current browser.\n *\n * @see [SpeechRecognition browser compatibility on MDN](https://developer.mozilla.org/en-US/docs/Web/API/SpeechRecognition#browser_compatibility)\n */\n readonly isSupported: Signal<boolean>;\n\n /**\n * Whether speech recognition is currently active and listening.\n */\n readonly isListening: Signal<boolean>;\n\n /**\n * Accumulated final transcript text.\n *\n * @see [SpeechRecognitionResult on MDN](https://developer.mozilla.org/en-US/docs/Web/API/SpeechRecognitionResult)\n */\n readonly text: Signal<string>;\n\n /**\n * In-progress interim transcript. Only populated when `interimResults` is `true`.\n *\n * @see [SpeechRecognition: interimResults on MDN](https://developer.mozilla.org/en-US/docs/Web/API/SpeechRecognition/interimResults)\n */\n readonly interimText: Signal<string>;\n\n /**\n * The last recognition error, or `null` if no error occurred.\n *\n * @see [SpeechRecognitionErrorEvent on MDN](https://developer.mozilla.org/en-US/docs/Web/API/SpeechRecognitionErrorEvent)\n */\n readonly error: Signal<SpeechRecognitionErrorEvent | Error | null>;\n\n /**\n * Start listening for speech input.\n *\n * @see [SpeechRecognition: start() on MDN](https://developer.mozilla.org/en-US/docs/Web/API/SpeechRecognition/start)\n */\n readonly start: () => void;\n\n /**\n * Stop listening and return any remaining results.\n *\n * @see [SpeechRecognition: stop() on MDN](https://developer.mozilla.org/en-US/docs/Web/API/SpeechRecognition/stop)\n */\n readonly stop: () => void;\n\n /**\n * Abort recognition immediately without returning results.\n *\n * @see [SpeechRecognition: abort() on MDN](https://developer.mozilla.org/en-US/docs/Web/API/SpeechRecognition/abort)\n */\n readonly abort: () => void;\n}\n\n/**\n * Signal-based wrapper around the [Speech Recognition API](https://developer.mozilla.org/en-US/docs/Web/API/SpeechRecognition).\n *\n * @param options - Optional configuration\n * @returns A SpeechRecognitionRef with isSupported, isListening, text, interimText, error signals and control methods\n *\n * @example\n * ```typescript\n * @Component({\n * template: `\n * @if (recognition.isSupported()) {\n * <button (click)=\"toggleRecognition()\">\n * {{ recognition.isListening() ? 'Stop' : 'Start' }} Recording\n * </button>\n * <p>{{ recognition.text() }}</p>\n * @if (recognition.interimText()) {\n * <p><em>{{ recognition.interimText() }}</em></p>\n * }\n * }\n * `\n * })\n * export class SpeechComponent {\n * readonly recognition = speechRecognition();\n *\n * toggleRecognition() {\n * if (this.recognition.isListening()) {\n * this.recognition.stop();\n * } else {\n * this.recognition.start();\n * }\n * }\n * }\n * ```\n */\nexport function speechRecognition(options?: SpeechRecognitionOptions): SpeechRecognitionRef {\n const { runInContext } = setupContext(options?.injector, speechRecognition);\n\n return runInContext(({ isBrowser, injector, onCleanup }) => {\n const isSupported = constSignal(\n isBrowser && ('SpeechRecognition' in window || 'webkitSpeechRecognition' in window)\n );\n\n if (!isSupported()) {\n return {\n isSupported,\n isListening: constSignal(false),\n text: constSignal(''),\n interimText: constSignal(''),\n error: constSignal(null),\n start: NOOP_FN,\n stop: NOOP_FN,\n abort: NOOP_FN,\n };\n }\n\n const SpeechRecognitionClass = window.SpeechRecognition || window.webkitSpeechRecognition;\n\n const recognition = new SpeechRecognitionClass();\n\n const {\n lang = 'en-US',\n interimResults = false,\n continuous = false,\n maxAlternatives = 1,\n } = options ?? {};\n\n recognition.lang = toValue(lang);\n recognition.continuous = continuous;\n recognition.interimResults = interimResults;\n recognition.maxAlternatives = maxAlternatives;\n\n const isListening = signal(false);\n const text = signal('');\n const interimText = signal('');\n const error = signal<SpeechRecognitionErrorEvent | Error | null>(null);\n\n const handleResult = (event: SpeechRecognitionEvent) => {\n let finalTranscript = '';\n let interimTranscript = '';\n\n for (let i = event.resultIndex; i < event.results.length; i++) {\n const result = event.results[i];\n const transcript = result[0]?.transcript || result.item(0)?.transcript || '';\n\n if (result.isFinal) {\n finalTranscript += transcript;\n } else {\n interimTranscript += transcript;\n }\n }\n\n if (finalTranscript) {\n text.update(t => (t ? t + ' ' : '') + finalTranscript);\n interimText.set('');\n } else if (interimTranscript) {\n interimText.set(interimTranscript);\n }\n };\n\n const handleError = (event: SpeechRecognitionErrorEvent) => {\n error.set(event);\n isListening.set(false);\n };\n\n const handleStart = () => {\n isListening.set(true);\n error.set(null);\n\n if (!continuous) {\n text.set('');\n interimText.set('');\n }\n };\n\n const handleEnd = () => {\n isListening.set(false);\n recognition.lang = toValue(lang);\n };\n\n recognition.onstart = handleStart;\n recognition.onend = handleEnd;\n recognition.onerror = handleError;\n recognition.onresult = handleResult;\n\n const start = () => {\n try {\n if (!untracked(isListening)) {\n recognition.start();\n }\n } catch (err) {\n error.set(err as Error);\n }\n };\n\n const stop = () => {\n if (untracked(isListening)) {\n recognition.stop();\n }\n };\n\n const abort = () => {\n if (untracked(isListening)) {\n recognition.abort();\n }\n };\n\n onCleanup(abort);\n\n if (isSignal(lang)) {\n watcher(lang, newLang => {\n if (!isListening()) {\n recognition.lang = newLang;\n }\n });\n }\n\n watcher(permissionState('microphone'), state => {\n if (state === 'denied') {\n abort();\n }\n });\n\n return {\n isSupported,\n isListening: isListening.asReadonly(),\n text: text.asReadonly(),\n interimText: interimText.asReadonly(),\n error: error.asReadonly(),\n start,\n stop,\n abort,\n };\n });\n}\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './index';\n"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"signality-core-browser-speech-recognition.mjs","sources":["../../../projects/core/browser/speech-recognition/index.ts","../../../projects/core/browser/speech-recognition/signality-core-browser-speech-recognition.ts"],"sourcesContent":["import { isSignal, type Signal, signal, untracked } from '@angular/core';\nimport { constSignal, NOOP_FN, setupContext, toValue } from '@signality/core/internal';\nimport type { MaybeSignal, WithInjector } from '@signality/core/types';\nimport { watcher } from '@signality/core/reactivity/watcher';\nimport { permissionState } from '@signality/core/browser/permission-state';\n\nexport interface SpeechRecognitionOptions extends WithInjector {\n /**\n * BCP 47 language tag for recognition (e.g. `'en-US'`).\n *\n * @default 'en-US'\n * @see [SpeechRecognition: lang on MDN](https://developer.mozilla.org/en-US/docs/Web/API/SpeechRecognition/lang)\n */\n readonly lang?: MaybeSignal<string>;\n\n /**\n * Whether to return interim (in-progress) results alongside final ones.\n *\n * @default false\n * @see [SpeechRecognition: interimResults on MDN](https://developer.mozilla.org/en-US/docs/Web/API/SpeechRecognition/interimResults)\n */\n readonly interimResults?: boolean;\n\n /**\n * Whether recognition continues after the user stops speaking.\n *\n * @default false\n * @see [SpeechRecognition: continuous on MDN](https://developer.mozilla.org/en-US/docs/Web/API/SpeechRecognition/continuous)\n */\n readonly continuous?: boolean;\n\n /**\n * Maximum number of alternative recognition results per utterance.\n *\n * @default 1\n * @see [SpeechRecognition: maxAlternatives on MDN](https://developer.mozilla.org/en-US/docs/Web/API/SpeechRecognition/maxAlternatives)\n */\n readonly maxAlternatives?: number;\n}\n\nexport interface SpeechRecognitionRef {\n /**\n * Whether the Speech Recognition API is supported in the current browser.\n *\n * @see [SpeechRecognition browser compatibility on MDN](https://developer.mozilla.org/en-US/docs/Web/API/SpeechRecognition#browser_compatibility)\n */\n readonly isSupported: Signal<boolean>;\n\n /**\n * Whether speech recognition is currently active and listening.\n */\n readonly isListening: Signal<boolean>;\n\n /**\n * Accumulated final transcript text.\n *\n * @see [SpeechRecognitionResult on MDN](https://developer.mozilla.org/en-US/docs/Web/API/SpeechRecognitionResult)\n */\n readonly text: Signal<string>;\n\n /**\n * In-progress interim transcript. Only populated when `interimResults` is `true`.\n *\n * @see [SpeechRecognition: interimResults on MDN](https://developer.mozilla.org/en-US/docs/Web/API/SpeechRecognition/interimResults)\n */\n readonly interimText: Signal<string>;\n\n /**\n * The last recognition error, or `null` if no error occurred.\n *\n * @see [SpeechRecognitionErrorEvent on MDN](https://developer.mozilla.org/en-US/docs/Web/API/SpeechRecognitionErrorEvent)\n */\n readonly error: Signal<SpeechRecognitionErrorEvent | Error | null>;\n\n /**\n * Start listening for speech input.\n *\n * @see [SpeechRecognition: start() on MDN](https://developer.mozilla.org/en-US/docs/Web/API/SpeechRecognition/start)\n */\n readonly start: () => void;\n\n /**\n * Stop listening and return any remaining results.\n *\n * @see [SpeechRecognition: stop() on MDN](https://developer.mozilla.org/en-US/docs/Web/API/SpeechRecognition/stop)\n */\n readonly stop: () => void;\n\n /**\n * Abort recognition immediately without returning results.\n *\n * @see [SpeechRecognition: abort() on MDN](https://developer.mozilla.org/en-US/docs/Web/API/SpeechRecognition/abort)\n */\n readonly abort: () => void;\n}\n\n/**\n * Signal-based wrapper around the [Speech Recognition API](https://developer.mozilla.org/en-US/docs/Web/API/SpeechRecognition).\n *\n * @param options - Optional configuration\n * @returns A SpeechRecognitionRef with isSupported, isListening, text, interimText, error signals and control methods\n *\n * @example\n * ```typescript\n * @Component({\n * template: `\n * @if (recognition.isSupported()) {\n * <button (click)=\"toggleRecognition()\">\n * {{ recognition.isListening() ? 'Stop' : 'Start' }} Recording\n * </button>\n * <p>{{ recognition.text() }}</p>\n * @if (recognition.interimText()) {\n * <p><em>{{ recognition.interimText() }}</em></p>\n * }\n * }\n * `\n * })\n * export class SpeechComponent {\n * readonly recognition = speechRecognition();\n *\n * toggleRecognition() {\n * if (this.recognition.isListening()) {\n * this.recognition.stop();\n * } else {\n * this.recognition.start();\n * }\n * }\n * }\n * ```\n */\nexport function speechRecognition(options?: SpeechRecognitionOptions): SpeechRecognitionRef {\n const { runInContext } = setupContext(options?.injector, speechRecognition);\n\n return runInContext(({ isBrowser, onCleanup }) => {\n const isSupported = constSignal(\n isBrowser && ('SpeechRecognition' in window || 'webkitSpeechRecognition' in window)\n );\n\n if (!isSupported()) {\n return {\n isSupported,\n isListening: constSignal(false),\n text: constSignal(''),\n interimText: constSignal(''),\n error: constSignal(null),\n start: NOOP_FN,\n stop: NOOP_FN,\n abort: NOOP_FN,\n };\n }\n\n const SpeechRecognitionClass = window.SpeechRecognition || window.webkitSpeechRecognition;\n\n const recognition = new SpeechRecognitionClass();\n\n const {\n lang = 'en-US',\n interimResults = false,\n continuous = false,\n maxAlternatives = 1,\n } = options ?? {};\n\n recognition.lang = toValue(lang);\n recognition.continuous = continuous;\n recognition.interimResults = interimResults;\n recognition.maxAlternatives = maxAlternatives;\n\n const isListening = signal(false);\n const text = signal('');\n const interimText = signal('');\n const error = signal<SpeechRecognitionErrorEvent | Error | null>(null);\n\n const handleResult = (event: SpeechRecognitionEvent) => {\n let finalTranscript = '';\n let interimTranscript = '';\n\n for (let i = event.resultIndex; i < event.results.length; i++) {\n const result = event.results[i];\n const transcript = result[0]?.transcript || result.item(0)?.transcript || '';\n\n if (result.isFinal) {\n finalTranscript += transcript;\n } else {\n interimTranscript += transcript;\n }\n }\n\n if (finalTranscript) {\n text.update(t => (t ? t + ' ' : '') + finalTranscript);\n interimText.set('');\n } else if (interimTranscript) {\n interimText.set(interimTranscript);\n }\n };\n\n const handleError = (event: SpeechRecognitionErrorEvent) => {\n error.set(event);\n isListening.set(false);\n };\n\n const handleStart = () => {\n isListening.set(true);\n error.set(null);\n\n if (!continuous) {\n text.set('');\n interimText.set('');\n }\n };\n\n const handleEnd = () => {\n isListening.set(false);\n recognition.lang = toValue(lang);\n };\n\n recognition.onstart = handleStart;\n recognition.onend = handleEnd;\n recognition.onerror = handleError;\n recognition.onresult = handleResult;\n\n const start = () => {\n try {\n if (!untracked(isListening)) {\n recognition.start();\n }\n } catch (err) {\n error.set(err as Error);\n }\n };\n\n const stop = () => {\n if (untracked(isListening)) {\n recognition.stop();\n }\n };\n\n const abort = () => {\n if (untracked(isListening)) {\n recognition.abort();\n }\n };\n\n onCleanup(abort);\n\n if (isSignal(lang)) {\n watcher(lang, newLang => {\n if (!isListening()) {\n recognition.lang = newLang;\n }\n });\n }\n\n watcher(permissionState('microphone'), state => {\n if (state === 'denied') {\n abort();\n }\n });\n\n return {\n isSupported,\n isListening: isListening.asReadonly(),\n text: text.asReadonly(),\n interimText: interimText.asReadonly(),\n error: error.asReadonly(),\n start,\n stop,\n abort,\n };\n });\n}\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './index';\n"],"names":[],"mappings":"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"}
|
|
@@ -28,7 +28,6 @@ export * from '@signality/core/browser/storage';
|
|
|
28
28
|
export * from '@signality/core/browser/text-direction';
|
|
29
29
|
export * from '@signality/core/browser/text-selection';
|
|
30
30
|
export * from '@signality/core/browser/vibration';
|
|
31
|
-
export * from '@signality/core/browser/wake-lock';
|
|
32
31
|
export * from '@signality/core/browser/web-notification';
|
|
33
32
|
export * from '@signality/core/browser/web-share';
|
|
34
33
|
export * from '@signality/core/browser/web-worker';
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"signality-core-browser.mjs","sources":["../../../projects/core/browser/signality-core-browser.ts"],"sourcesContent":["/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './index';\n"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"signality-core-browser.mjs","sources":["../../../projects/core/browser/signality-core-browser.ts"],"sourcesContent":["/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './index';\n"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;;AAEG"}
|
|
@@ -36,17 +36,19 @@ function interval(callback, intervalMs, options) {
|
|
|
36
36
|
return NOOP_EFFECT_REF;
|
|
37
37
|
}
|
|
38
38
|
let intervalId;
|
|
39
|
+
let watcherRef = null;
|
|
39
40
|
const start = () => {
|
|
40
41
|
clearInterval(intervalId);
|
|
41
42
|
const ms = toValue.untracked(intervalMs);
|
|
42
43
|
intervalId = ms > 0 ? setInterval(callback, ms) : undefined;
|
|
43
44
|
};
|
|
44
45
|
if (isSignal(intervalMs)) {
|
|
45
|
-
watcher(intervalMs, start);
|
|
46
|
+
watcherRef = watcher(intervalMs, start);
|
|
46
47
|
}
|
|
47
48
|
const destroy = () => {
|
|
48
49
|
clearInterval(intervalId);
|
|
49
50
|
intervalId = undefined;
|
|
51
|
+
watcherRef?.destroy();
|
|
50
52
|
};
|
|
51
53
|
onCleanup(destroy);
|
|
52
54
|
if (options?.immediate) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"signality-core-scheduling-interval.mjs","sources":["../../../projects/core/scheduling/interval/index.ts","../../../projects/core/scheduling/interval/signality-core-scheduling-interval.ts"],"sourcesContent":["import { isSignal } from '@angular/core';\nimport { NOOP_EFFECT_REF, setupContext, type Timer, toValue } from '@signality/core/internal';\nimport type { MaybeSignal, WithInjector } from '@signality/core/types';\nimport { watcher } from '@signality/core/reactivity/watcher';\n\nexport interface IntervalOptions extends WithInjector {\n /**\n * Call the callback immediately, without waiting for the first tick.\n *\n * @default false\n */\n readonly immediate?: boolean;\n}\n\nexport interface IntervalRef {\n /**\n * Stop the interval permanently.\n */\n readonly destroy: () => void;\n}\n\n/**\n * Signal-based wrapper around [`setInterval`](https://developer.mozilla.org/en-US/docs/Web/API/Window/setInterval).\n * Creates a reactive interval that executes a callback at specified intervals.\n * The interval starts immediately upon creation and can be stopped with `destroy()`.\n *\n * @param callback - Function to execute on each interval tick\n * @param intervalMs - Interval duration in milliseconds (can be a reactive signal)\n * @param options - Optional configuration\n * @returns An IntervalRef with a `destroy` method to stop the interval\n *\n * @example\n * ```typescript\n * @Component({\n * template: `\n * <p>Ticks: {{ ticks() }}</p>\n * <button (click)=\"polling.destroy()\">Stop</button>\n * `,\n * })\n * export class PeriodicTask {\n * readonly ticks = signal(0);\n *\n * readonly polling = interval(() => {\n * this.ticks.update(n => n + 1);\n * }, 5000);\n * }\n * ```\n */\nexport function interval(\n callback: () => void,\n intervalMs: MaybeSignal<number>,\n options?: IntervalOptions\n): IntervalRef {\n const { runInContext } = setupContext(options?.injector, interval);\n\n return runInContext(({ isServer, onCleanup }) => {\n if (isServer) {\n return NOOP_EFFECT_REF;\n }\n\n let intervalId: Timer;\n\n const start = () => {\n clearInterval(intervalId);\n\n const ms = toValue.untracked(intervalMs);\n intervalId = ms > 0 ? setInterval(callback, ms) : undefined;\n };\n\n if (isSignal(intervalMs)) {\n watcher(intervalMs, start);\n }\n\n const destroy = () => {\n clearInterval(intervalId);\n intervalId = undefined;\n };\n\n onCleanup(destroy);\n\n if (options?.immediate) {\n callback();\n }\n\n start();\n\n return { destroy };\n });\n}\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './index';\n"],"names":[],"mappings":";;;;AAqBA;;;;;;;;;;;;;;;;;;;;;;;;;;AA0BG;SACa,QAAQ,CACtB,QAAoB,EACpB,UAA+B,EAC/B,OAAyB,EAAA;AAEzB,IAAA,MAAM,EAAE,YAAY,EAAE,GAAG,YAAY,CAAC,OAAO,EAAE,QAAQ,EAAE,QAAQ,CAAC;IAElE,OAAO,YAAY,CAAC,CAAC,EAAE,QAAQ,EAAE,SAAS,EAAE,KAAI;QAC9C,IAAI,QAAQ,EAAE;AACZ,YAAA,OAAO,eAAe;QACxB;AAEA,QAAA,IAAI,UAAiB;
|
|
1
|
+
{"version":3,"file":"signality-core-scheduling-interval.mjs","sources":["../../../projects/core/scheduling/interval/index.ts","../../../projects/core/scheduling/interval/signality-core-scheduling-interval.ts"],"sourcesContent":["import { isSignal } from '@angular/core';\nimport { NOOP_EFFECT_REF, setupContext, type Timer, toValue } from '@signality/core/internal';\nimport type { MaybeSignal, WithInjector } from '@signality/core/types';\nimport { watcher, type WatcherRef } from '@signality/core/reactivity/watcher';\n\nexport interface IntervalOptions extends WithInjector {\n /**\n * Call the callback immediately, without waiting for the first tick.\n *\n * @default false\n */\n readonly immediate?: boolean;\n}\n\nexport interface IntervalRef {\n /**\n * Stop the interval permanently.\n */\n readonly destroy: () => void;\n}\n\n/**\n * Signal-based wrapper around [`setInterval`](https://developer.mozilla.org/en-US/docs/Web/API/Window/setInterval).\n * Creates a reactive interval that executes a callback at specified intervals.\n * The interval starts immediately upon creation and can be stopped with `destroy()`.\n *\n * @param callback - Function to execute on each interval tick\n * @param intervalMs - Interval duration in milliseconds (can be a reactive signal)\n * @param options - Optional configuration\n * @returns An IntervalRef with a `destroy` method to stop the interval\n *\n * @example\n * ```typescript\n * @Component({\n * template: `\n * <p>Ticks: {{ ticks() }}</p>\n * <button (click)=\"polling.destroy()\">Stop</button>\n * `,\n * })\n * export class PeriodicTask {\n * readonly ticks = signal(0);\n *\n * readonly polling = interval(() => {\n * this.ticks.update(n => n + 1);\n * }, 5000);\n * }\n * ```\n */\nexport function interval(\n callback: () => void,\n intervalMs: MaybeSignal<number>,\n options?: IntervalOptions\n): IntervalRef {\n const { runInContext } = setupContext(options?.injector, interval);\n\n return runInContext(({ isServer, onCleanup }) => {\n if (isServer) {\n return NOOP_EFFECT_REF;\n }\n\n let intervalId: Timer;\n let watcherRef: WatcherRef | null = null;\n\n const start = () => {\n clearInterval(intervalId);\n\n const ms = toValue.untracked(intervalMs);\n intervalId = ms > 0 ? setInterval(callback, ms) : undefined;\n };\n\n if (isSignal(intervalMs)) {\n watcherRef = watcher(intervalMs, start);\n }\n\n const destroy = () => {\n clearInterval(intervalId);\n intervalId = undefined;\n watcherRef?.destroy();\n };\n\n onCleanup(destroy);\n\n if (options?.immediate) {\n callback();\n }\n\n start();\n\n return { destroy };\n });\n}\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './index';\n"],"names":[],"mappings":";;;;AAqBA;;;;;;;;;;;;;;;;;;;;;;;;;;AA0BG;SACa,QAAQ,CACtB,QAAoB,EACpB,UAA+B,EAC/B,OAAyB,EAAA;AAEzB,IAAA,MAAM,EAAE,YAAY,EAAE,GAAG,YAAY,CAAC,OAAO,EAAE,QAAQ,EAAE,QAAQ,CAAC;IAElE,OAAO,YAAY,CAAC,CAAC,EAAE,QAAQ,EAAE,SAAS,EAAE,KAAI;QAC9C,IAAI,QAAQ,EAAE;AACZ,YAAA,OAAO,eAAe;QACxB;AAEA,QAAA,IAAI,UAAiB;QACrB,IAAI,UAAU,GAAsB,IAAI;QAExC,MAAM,KAAK,GAAG,MAAK;YACjB,aAAa,CAAC,UAAU,CAAC;YAEzB,MAAM,EAAE,GAAG,OAAO,CAAC,SAAS,CAAC,UAAU,CAAC;AACxC,YAAA,UAAU,GAAG,EAAE,GAAG,CAAC,GAAG,WAAW,CAAC,QAAQ,EAAE,EAAE,CAAC,GAAG,SAAS;AAC7D,QAAA,CAAC;AAED,QAAA,IAAI,QAAQ,CAAC,UAAU,CAAC,EAAE;AACxB,YAAA,UAAU,GAAG,OAAO,CAAC,UAAU,EAAE,KAAK,CAAC;QACzC;QAEA,MAAM,OAAO,GAAG,MAAK;YACnB,aAAa,CAAC,UAAU,CAAC;YACzB,UAAU,GAAG,SAAS;YACtB,UAAU,EAAE,OAAO,EAAE;AACvB,QAAA,CAAC;QAED,SAAS,CAAC,OAAO,CAAC;AAElB,QAAA,IAAI,OAAO,EAAE,SAAS,EAAE;AACtB,YAAA,QAAQ,EAAE;QACZ;AAEA,QAAA,KAAK,EAAE;QAEP,OAAO,EAAE,OAAO,EAAE;AACpB,IAAA,CAAC,CAAC;AACJ;;AC1FA;;AAEG;;;;"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@signality/core",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.1.0",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"author": "Vyacheslav Borodin <https://github.com/vs-borodin>",
|
|
6
6
|
"description": "A foundational toolkit for Angular Signals",
|
|
@@ -23,11 +23,11 @@
|
|
|
23
23
|
"homepage": "https://signality.dev",
|
|
24
24
|
"sideEffects": false,
|
|
25
25
|
"peerDependencies": {
|
|
26
|
-
"@angular/common": ">=
|
|
27
|
-
"@angular/core": ">=
|
|
28
|
-
"@angular/forms": ">=
|
|
29
|
-
"@angular/router": ">=
|
|
30
|
-
"@angular/platform-browser": ">=
|
|
26
|
+
"@angular/common": ">=20.0.0",
|
|
27
|
+
"@angular/core": ">=20.0.0",
|
|
28
|
+
"@angular/forms": ">=20.0.0",
|
|
29
|
+
"@angular/router": ">=20.0.0",
|
|
30
|
+
"@angular/platform-browser": ">=20.0.0",
|
|
31
31
|
"rxjs": ">=7.8.1"
|
|
32
32
|
},
|
|
33
33
|
"module": "fesm2022/signality-core.mjs",
|
|
@@ -196,10 +196,6 @@
|
|
|
196
196
|
"types": "./browser/vibration/index.d.ts",
|
|
197
197
|
"default": "./fesm2022/signality-core-browser-vibration.mjs"
|
|
198
198
|
},
|
|
199
|
-
"./browser/wake-lock": {
|
|
200
|
-
"types": "./browser/wake-lock/index.d.ts",
|
|
201
|
-
"default": "./fesm2022/signality-core-browser-wake-lock.mjs"
|
|
202
|
-
},
|
|
203
199
|
"./browser/web-notification": {
|
|
204
200
|
"types": "./browser/web-notification/index.d.ts",
|
|
205
201
|
"default": "./fesm2022/signality-core-browser-web-notification.mjs"
|
|
@@ -1,76 +0,0 @@
|
|
|
1
|
-
import { type Signal } from '@angular/core';
|
|
2
|
-
import type { WithInjector } from '@signality/core/types';
|
|
3
|
-
export interface WakeLockOptions extends WithInjector {
|
|
4
|
-
/**
|
|
5
|
-
* Whether to automatically reacquire the wake lock when the document becomes visible again
|
|
6
|
-
* after being hidden (e.g. tab switch or screen lock).
|
|
7
|
-
*
|
|
8
|
-
* Defaults to `true`.
|
|
9
|
-
*
|
|
10
|
-
* @see [Page Visibility API on MDN](https://developer.mozilla.org/en-US/docs/Web/API/Page_Visibility_API)
|
|
11
|
-
*/
|
|
12
|
-
readonly autoReacquire?: boolean;
|
|
13
|
-
}
|
|
14
|
-
export interface WakeLockRef {
|
|
15
|
-
/**
|
|
16
|
-
* Whether the Screen Wake Lock API is supported in the current browser.
|
|
17
|
-
*
|
|
18
|
-
* @see [Screen Wake Lock API browser compatibility on MDN](https://developer.mozilla.org/en-US/docs/Web/API/Screen_Wake_Lock_API#browser_compatibility)
|
|
19
|
-
*/
|
|
20
|
-
readonly isSupported: Signal<boolean>;
|
|
21
|
-
/**
|
|
22
|
-
* Whether the wake lock is currently active.
|
|
23
|
-
* `false` when the sentinel is released or the document is not visible.
|
|
24
|
-
*/
|
|
25
|
-
readonly isActive: Signal<boolean>;
|
|
26
|
-
/**
|
|
27
|
-
* The active `WakeLockSentinel` instance, or `null` when no wake lock is held.
|
|
28
|
-
*
|
|
29
|
-
* @see [WakeLockSentinel on MDN](https://developer.mozilla.org/en-US/docs/Web/API/WakeLockSentinel)
|
|
30
|
-
*/
|
|
31
|
-
readonly sentinel: Signal<WakeLockSentinel | null>;
|
|
32
|
-
/**
|
|
33
|
-
* Request a wake lock. No-op if a lock is already active.
|
|
34
|
-
* If the document is not visible, the request will be deferred until it becomes visible
|
|
35
|
-
* (only when `autoReacquire` is `true`).
|
|
36
|
-
*
|
|
37
|
-
* @see [WakeLock.request() on MDN](https://developer.mozilla.org/en-US/docs/Web/API/WakeLock/request)
|
|
38
|
-
*/
|
|
39
|
-
readonly request: () => Promise<void>;
|
|
40
|
-
/**
|
|
41
|
-
* Request a wake lock unconditionally, releasing the existing sentinel first if present.
|
|
42
|
-
*
|
|
43
|
-
* @see [WakeLockSentinel.release() on MDN](https://developer.mozilla.org/en-US/docs/Web/API/WakeLockSentinel/release)
|
|
44
|
-
*/
|
|
45
|
-
readonly forceRequest: () => Promise<void>;
|
|
46
|
-
/**
|
|
47
|
-
* Release the active wake lock and clear the sentinel.
|
|
48
|
-
*
|
|
49
|
-
* @see [WakeLockSentinel.release() on MDN](https://developer.mozilla.org/en-US/docs/Web/API/WakeLockSentinel/release)
|
|
50
|
-
*/
|
|
51
|
-
readonly release: () => Promise<void>;
|
|
52
|
-
}
|
|
53
|
-
/**
|
|
54
|
-
* Signal-based wrapper around the [Screen Wake Lock API](https://developer.mozilla.org/en-US/docs/Web/API/Screen_Wake_Lock_API).
|
|
55
|
-
* Prevents the screen from turning off while the wake lock is active.
|
|
56
|
-
*
|
|
57
|
-
* @param options - Optional configuration
|
|
58
|
-
* @returns A WakeLockRef with isSupported, isActive, sentinel signals and control methods
|
|
59
|
-
*
|
|
60
|
-
* @example
|
|
61
|
-
* ```typescript
|
|
62
|
-
* @Component({
|
|
63
|
-
* template: `
|
|
64
|
-
* @if (wl.isSupported()) {
|
|
65
|
-
* <button (click)="wl.request()">Keep screen on</button>
|
|
66
|
-
* <button (click)="wl.release()">Release</button>
|
|
67
|
-
* <p>Active: {{ wl.isActive() }}</p>
|
|
68
|
-
* }
|
|
69
|
-
* `
|
|
70
|
-
* })
|
|
71
|
-
* export class WakeLockDemo {
|
|
72
|
-
* readonly wl = wakeLock();
|
|
73
|
-
* }
|
|
74
|
-
* ```
|
|
75
|
-
*/
|
|
76
|
-
export declare function wakeLock(options?: WakeLockOptions): WakeLockRef;
|
|
@@ -1,166 +0,0 @@
|
|
|
1
|
-
import { signal, inject, computed, untracked, effect } from '@angular/core';
|
|
2
|
-
import { setupContext, constSignal, NOOP_ASYNC_FN } from '@signality/core/internal';
|
|
3
|
-
import { setupSync, listener } from '@signality/core/browser/listener';
|
|
4
|
-
import { PAGE_VISIBILITY } from '@signality/core/browser/page-visibility';
|
|
5
|
-
|
|
6
|
-
/**
|
|
7
|
-
* Signal-based wrapper around the [Screen Wake Lock API](https://developer.mozilla.org/en-US/docs/Web/API/Screen_Wake_Lock_API).
|
|
8
|
-
* Prevents the screen from turning off while the wake lock is active.
|
|
9
|
-
*
|
|
10
|
-
* @param options - Optional configuration
|
|
11
|
-
* @returns A WakeLockRef with isSupported, isActive, sentinel signals and control methods
|
|
12
|
-
*
|
|
13
|
-
* @example
|
|
14
|
-
* ```typescript
|
|
15
|
-
* @Component({
|
|
16
|
-
* template: `
|
|
17
|
-
* @if (wl.isSupported()) {
|
|
18
|
-
* <button (click)="wl.request()">Keep screen on</button>
|
|
19
|
-
* <button (click)="wl.release()">Release</button>
|
|
20
|
-
* <p>Active: {{ wl.isActive() }}</p>
|
|
21
|
-
* }
|
|
22
|
-
* `
|
|
23
|
-
* })
|
|
24
|
-
* export class WakeLockDemo {
|
|
25
|
-
* readonly wl = wakeLock();
|
|
26
|
-
* }
|
|
27
|
-
* ```
|
|
28
|
-
*/
|
|
29
|
-
function wakeLock(options) {
|
|
30
|
-
const { runInContext } = setupContext(options?.injector, wakeLock);
|
|
31
|
-
return runInContext(({ isBrowser, onCleanup, injector }) => {
|
|
32
|
-
const sentinel = signal(null, ...(ngDevMode ? [{ debugName: "sentinel" }] : []));
|
|
33
|
-
const pendingRequest = signal(false, ...(ngDevMode ? [{ debugName: "pendingRequest" }] : []));
|
|
34
|
-
const isSupported = constSignal(isBrowser &&
|
|
35
|
-
'wakeLock' in navigator &&
|
|
36
|
-
typeof navigator.wakeLock?.request === 'function');
|
|
37
|
-
if (!isSupported()) {
|
|
38
|
-
return {
|
|
39
|
-
isSupported,
|
|
40
|
-
isActive: constSignal(false),
|
|
41
|
-
sentinel: sentinel.asReadonly(),
|
|
42
|
-
request: NOOP_ASYNC_FN,
|
|
43
|
-
forceRequest: NOOP_ASYNC_FN,
|
|
44
|
-
release: NOOP_ASYNC_FN,
|
|
45
|
-
};
|
|
46
|
-
}
|
|
47
|
-
const visibility = inject(PAGE_VISIBILITY);
|
|
48
|
-
const { autoReacquire = true } = options ?? {};
|
|
49
|
-
const isActive = computed(() => {
|
|
50
|
-
const s = sentinel();
|
|
51
|
-
return !!s && !s.released && visibility() === 'visible';
|
|
52
|
-
}, ...(ngDevMode ? [{ debugName: "isActive" }] : []));
|
|
53
|
-
let listenerRef = null;
|
|
54
|
-
let isRequesting = false;
|
|
55
|
-
const forceRequest = async () => {
|
|
56
|
-
if (isRequesting)
|
|
57
|
-
return;
|
|
58
|
-
isRequesting = true;
|
|
59
|
-
try {
|
|
60
|
-
const currentSentinel = untracked(sentinel);
|
|
61
|
-
if (currentSentinel) {
|
|
62
|
-
if (listenerRef) {
|
|
63
|
-
listenerRef.destroy();
|
|
64
|
-
listenerRef = null;
|
|
65
|
-
}
|
|
66
|
-
if (!currentSentinel.released) {
|
|
67
|
-
await currentSentinel.release();
|
|
68
|
-
}
|
|
69
|
-
}
|
|
70
|
-
if (untracked(visibility) === 'visible') {
|
|
71
|
-
const newSentinel = await navigator.wakeLock.request('screen');
|
|
72
|
-
sentinel.set(newSentinel);
|
|
73
|
-
listenerRef = setupSync(() => listener(newSentinel, 'release', () => {
|
|
74
|
-
pendingRequest.set(false);
|
|
75
|
-
sentinel.set(null);
|
|
76
|
-
listenerRef = null;
|
|
77
|
-
}, { injector }));
|
|
78
|
-
}
|
|
79
|
-
}
|
|
80
|
-
catch (err) {
|
|
81
|
-
sentinel.set(null);
|
|
82
|
-
pendingRequest.set(false);
|
|
83
|
-
if (listenerRef) {
|
|
84
|
-
listenerRef.destroy();
|
|
85
|
-
listenerRef = null;
|
|
86
|
-
}
|
|
87
|
-
if (ngDevMode) {
|
|
88
|
-
console.warn('[wakeLock] Failed to acquire wake lock.', err);
|
|
89
|
-
}
|
|
90
|
-
}
|
|
91
|
-
finally {
|
|
92
|
-
isRequesting = false;
|
|
93
|
-
}
|
|
94
|
-
};
|
|
95
|
-
const request = async () => {
|
|
96
|
-
if (untracked(visibility) === 'visible') {
|
|
97
|
-
await forceRequest();
|
|
98
|
-
}
|
|
99
|
-
else {
|
|
100
|
-
pendingRequest.set(true);
|
|
101
|
-
}
|
|
102
|
-
};
|
|
103
|
-
const release = async () => {
|
|
104
|
-
pendingRequest.set(false);
|
|
105
|
-
const currentSentinel = untracked(sentinel);
|
|
106
|
-
sentinel.set(null);
|
|
107
|
-
if (currentSentinel) {
|
|
108
|
-
if (listenerRef) {
|
|
109
|
-
listenerRef.destroy();
|
|
110
|
-
listenerRef = null;
|
|
111
|
-
}
|
|
112
|
-
if (!currentSentinel.released) {
|
|
113
|
-
try {
|
|
114
|
-
await currentSentinel.release();
|
|
115
|
-
}
|
|
116
|
-
catch (err) {
|
|
117
|
-
if (ngDevMode) {
|
|
118
|
-
console.warn('[wakeLock] Failed to release wake lock.', err);
|
|
119
|
-
}
|
|
120
|
-
}
|
|
121
|
-
}
|
|
122
|
-
}
|
|
123
|
-
};
|
|
124
|
-
if (autoReacquire) {
|
|
125
|
-
effect(() => {
|
|
126
|
-
const isVisible = visibility() === 'visible';
|
|
127
|
-
const isPending = pendingRequest();
|
|
128
|
-
if (isVisible && isPending) {
|
|
129
|
-
pendingRequest.set(false);
|
|
130
|
-
forceRequest().catch(() => {
|
|
131
|
-
/* handled inside forceRequest */
|
|
132
|
-
});
|
|
133
|
-
}
|
|
134
|
-
});
|
|
135
|
-
}
|
|
136
|
-
onCleanup(() => {
|
|
137
|
-
const currentSentinel = untracked(sentinel);
|
|
138
|
-
if (currentSentinel) {
|
|
139
|
-
if (listenerRef) {
|
|
140
|
-
listenerRef.destroy();
|
|
141
|
-
listenerRef = null;
|
|
142
|
-
}
|
|
143
|
-
if (!currentSentinel.released) {
|
|
144
|
-
currentSentinel.release().catch(() => {
|
|
145
|
-
/* ignore errors */
|
|
146
|
-
});
|
|
147
|
-
}
|
|
148
|
-
}
|
|
149
|
-
});
|
|
150
|
-
return {
|
|
151
|
-
isSupported,
|
|
152
|
-
isActive,
|
|
153
|
-
sentinel: sentinel.asReadonly(),
|
|
154
|
-
request,
|
|
155
|
-
forceRequest,
|
|
156
|
-
release,
|
|
157
|
-
};
|
|
158
|
-
});
|
|
159
|
-
}
|
|
160
|
-
|
|
161
|
-
/**
|
|
162
|
-
* Generated bundle index. Do not edit.
|
|
163
|
-
*/
|
|
164
|
-
|
|
165
|
-
export { wakeLock };
|
|
166
|
-
//# sourceMappingURL=signality-core-browser-wake-lock.mjs.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"signality-core-browser-wake-lock.mjs","sources":["../../../projects/core/browser/wake-lock/index.ts","../../../projects/core/browser/wake-lock/signality-core-browser-wake-lock.ts"],"sourcesContent":["import { computed, effect, inject, type Signal, signal, untracked } from '@angular/core';\nimport { constSignal, NOOP_ASYNC_FN, setupContext } from '@signality/core/internal';\nimport type { WithInjector } from '@signality/core/types';\nimport { listener, type ListenerRef, setupSync } from '@signality/core/browser/listener';\nimport { PAGE_VISIBILITY } from '@signality/core/browser/page-visibility';\n\nexport interface WakeLockOptions extends WithInjector {\n /**\n * Whether to automatically reacquire the wake lock when the document becomes visible again\n * after being hidden (e.g. tab switch or screen lock).\n *\n * Defaults to `true`.\n *\n * @see [Page Visibility API on MDN](https://developer.mozilla.org/en-US/docs/Web/API/Page_Visibility_API)\n */\n readonly autoReacquire?: boolean;\n}\n\nexport interface WakeLockRef {\n /**\n * Whether the Screen Wake Lock API is supported in the current browser.\n *\n * @see [Screen Wake Lock API browser compatibility on MDN](https://developer.mozilla.org/en-US/docs/Web/API/Screen_Wake_Lock_API#browser_compatibility)\n */\n readonly isSupported: Signal<boolean>;\n\n /**\n * Whether the wake lock is currently active.\n * `false` when the sentinel is released or the document is not visible.\n */\n readonly isActive: Signal<boolean>;\n\n /**\n * The active `WakeLockSentinel` instance, or `null` when no wake lock is held.\n *\n * @see [WakeLockSentinel on MDN](https://developer.mozilla.org/en-US/docs/Web/API/WakeLockSentinel)\n */\n readonly sentinel: Signal<WakeLockSentinel | null>;\n\n /**\n * Request a wake lock. No-op if a lock is already active.\n * If the document is not visible, the request will be deferred until it becomes visible\n * (only when `autoReacquire` is `true`).\n *\n * @see [WakeLock.request() on MDN](https://developer.mozilla.org/en-US/docs/Web/API/WakeLock/request)\n */\n readonly request: () => Promise<void>;\n\n /**\n * Request a wake lock unconditionally, releasing the existing sentinel first if present.\n *\n * @see [WakeLockSentinel.release() on MDN](https://developer.mozilla.org/en-US/docs/Web/API/WakeLockSentinel/release)\n */\n readonly forceRequest: () => Promise<void>;\n\n /**\n * Release the active wake lock and clear the sentinel.\n *\n * @see [WakeLockSentinel.release() on MDN](https://developer.mozilla.org/en-US/docs/Web/API/WakeLockSentinel/release)\n */\n readonly release: () => Promise<void>;\n}\n\n/**\n * Signal-based wrapper around the [Screen Wake Lock API](https://developer.mozilla.org/en-US/docs/Web/API/Screen_Wake_Lock_API).\n * Prevents the screen from turning off while the wake lock is active.\n *\n * @param options - Optional configuration\n * @returns A WakeLockRef with isSupported, isActive, sentinel signals and control methods\n *\n * @example\n * ```typescript\n * @Component({\n * template: `\n * @if (wl.isSupported()) {\n * <button (click)=\"wl.request()\">Keep screen on</button>\n * <button (click)=\"wl.release()\">Release</button>\n * <p>Active: {{ wl.isActive() }}</p>\n * }\n * `\n * })\n * export class WakeLockDemo {\n * readonly wl = wakeLock();\n * }\n * ```\n */\nexport function wakeLock(options?: WakeLockOptions): WakeLockRef {\n const { runInContext } = setupContext(options?.injector, wakeLock);\n\n return runInContext(({ isBrowser, onCleanup, injector }) => {\n const sentinel = signal<WakeLockSentinel | null>(null);\n const pendingRequest = signal(false);\n\n const isSupported = constSignal(\n isBrowser &&\n 'wakeLock' in navigator &&\n typeof (navigator as NavigatorWithWakeLock).wakeLock?.request === 'function'\n );\n\n if (!isSupported()) {\n return {\n isSupported,\n isActive: constSignal(false),\n sentinel: sentinel.asReadonly(),\n request: NOOP_ASYNC_FN,\n forceRequest: NOOP_ASYNC_FN,\n release: NOOP_ASYNC_FN,\n };\n }\n\n const visibility = inject(PAGE_VISIBILITY);\n\n const { autoReacquire = true } = options ?? {};\n\n const isActive = computed(() => {\n const s = sentinel();\n return !!s && !s.released && visibility() === 'visible';\n });\n\n let listenerRef: ListenerRef | null = null;\n let isRequesting = false;\n\n const forceRequest = async (): Promise<void> => {\n if (isRequesting) return;\n isRequesting = true;\n\n try {\n const currentSentinel = untracked(sentinel);\n\n if (currentSentinel) {\n if (listenerRef) {\n listenerRef.destroy();\n listenerRef = null;\n }\n\n if (!currentSentinel.released) {\n await currentSentinel.release();\n }\n }\n\n if (untracked(visibility) === 'visible') {\n const newSentinel = await (navigator as NavigatorWithWakeLock).wakeLock.request('screen');\n\n sentinel.set(newSentinel);\n\n listenerRef = setupSync(() =>\n listener(\n newSentinel,\n 'release',\n () => {\n pendingRequest.set(false);\n sentinel.set(null);\n listenerRef = null;\n },\n { injector }\n )\n );\n }\n } catch (err) {\n sentinel.set(null);\n pendingRequest.set(false);\n\n if (listenerRef) {\n listenerRef.destroy();\n listenerRef = null;\n }\n\n if (ngDevMode) {\n console.warn('[wakeLock] Failed to acquire wake lock.', err);\n }\n } finally {\n isRequesting = false;\n }\n };\n\n const request = async (): Promise<void> => {\n if (untracked(visibility) === 'visible') {\n await forceRequest();\n } else {\n pendingRequest.set(true);\n }\n };\n\n const release = async (): Promise<void> => {\n pendingRequest.set(false);\n\n const currentSentinel = untracked(sentinel);\n\n sentinel.set(null);\n\n if (currentSentinel) {\n if (listenerRef) {\n listenerRef.destroy();\n listenerRef = null;\n }\n if (!currentSentinel.released) {\n try {\n await currentSentinel.release();\n } catch (err) {\n if (ngDevMode) {\n console.warn('[wakeLock] Failed to release wake lock.', err);\n }\n }\n }\n }\n };\n\n if (autoReacquire) {\n effect(() => {\n const isVisible = visibility() === 'visible';\n const isPending = pendingRequest();\n\n if (isVisible && isPending) {\n pendingRequest.set(false);\n forceRequest().catch(() => {\n /* handled inside forceRequest */\n });\n }\n });\n }\n\n onCleanup(() => {\n const currentSentinel = untracked(sentinel);\n if (currentSentinel) {\n if (listenerRef) {\n listenerRef.destroy();\n listenerRef = null;\n }\n if (!currentSentinel.released) {\n currentSentinel.release().catch(() => {\n /* ignore errors */\n });\n }\n }\n });\n\n return {\n isSupported,\n isActive,\n sentinel: sentinel.asReadonly(),\n request,\n forceRequest,\n release,\n };\n });\n}\n\ninterface NavigatorWithWakeLock extends Navigator {\n readonly wakeLock: {\n readonly request: (type: 'screen') => Promise<WakeLockSentinel>;\n };\n}\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './index';\n"],"names":[],"mappings":"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"}
|