@symbiote-native/sensors 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.
Files changed (264) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +138 -0
  3. package/build/angular/index.d.ts +16 -0
  4. package/build/angular/index.js +12 -0
  5. package/build/angular/services/accelerometer.service/index.d.ts +6 -0
  6. package/build/angular/services/accelerometer.service/index.js +81 -0
  7. package/build/angular/services/barometer.service/index.d.ts +6 -0
  8. package/build/angular/services/barometer.service/index.js +81 -0
  9. package/build/angular/services/device-motion.service/index.d.ts +6 -0
  10. package/build/angular/services/device-motion.service/index.js +81 -0
  11. package/build/angular/services/gyroscope.service/index.d.ts +6 -0
  12. package/build/angular/services/gyroscope.service/index.js +81 -0
  13. package/build/angular/services/light-sensor.service/index.d.ts +6 -0
  14. package/build/angular/services/light-sensor.service/index.js +81 -0
  15. package/build/angular/services/magnetometer-uncalibrated.service/index.d.ts +6 -0
  16. package/build/angular/services/magnetometer-uncalibrated.service/index.js +81 -0
  17. package/build/angular/services/magnetometer.service/index.d.ts +6 -0
  18. package/build/angular/services/magnetometer.service/index.js +81 -0
  19. package/build/angular/services/pedometer.service/index.d.ts +6 -0
  20. package/build/angular/services/pedometer.service/index.js +76 -0
  21. package/build/core/accelerometer.d.ts +10 -0
  22. package/build/core/accelerometer.js +6 -0
  23. package/build/core/barometer.d.ts +9 -0
  24. package/build/core/barometer.js +6 -0
  25. package/build/core/device-motion.d.ts +40 -0
  26. package/build/core/device-motion.js +21 -0
  27. package/build/core/device-sensor.d.ts +27 -0
  28. package/build/core/device-sensor.js +61 -0
  29. package/build/core/gyroscope.d.ts +10 -0
  30. package/build/core/gyroscope.js +6 -0
  31. package/build/core/index.d.ts +11 -0
  32. package/build/core/index.js +10 -0
  33. package/build/core/light-sensor.d.ts +8 -0
  34. package/build/core/light-sensor.js +6 -0
  35. package/build/core/magnetometer-uncalibrated.d.ts +10 -0
  36. package/build/core/magnetometer-uncalibrated.js +6 -0
  37. package/build/core/magnetometer.d.ts +10 -0
  38. package/build/core/magnetometer.js +6 -0
  39. package/build/core/native/exponent-accelerometer.d.ts +3 -0
  40. package/build/core/native/exponent-accelerometer.js +3 -0
  41. package/build/core/native/exponent-barometer.d.ts +3 -0
  42. package/build/core/native/exponent-barometer.js +3 -0
  43. package/build/core/native/exponent-device-motion.d.ts +7 -0
  44. package/build/core/native/exponent-device-motion.js +3 -0
  45. package/build/core/native/exponent-gyroscope.d.ts +3 -0
  46. package/build/core/native/exponent-gyroscope.js +3 -0
  47. package/build/core/native/exponent-light-sensor/index.android.d.ts +3 -0
  48. package/build/core/native/exponent-light-sensor/index.android.js +3 -0
  49. package/build/core/native/exponent-light-sensor/index.d.ts +1 -0
  50. package/build/core/native/exponent-light-sensor/index.ios.d.ts +3 -0
  51. package/build/core/native/exponent-light-sensor/index.ios.js +6 -0
  52. package/build/core/native/exponent-light-sensor/index.js +5 -0
  53. package/build/core/native/exponent-magnetometer-uncalibrated.d.ts +3 -0
  54. package/build/core/native/exponent-magnetometer-uncalibrated.js +3 -0
  55. package/build/core/native/exponent-magnetometer.d.ts +3 -0
  56. package/build/core/native/exponent-magnetometer.js +3 -0
  57. package/build/core/native/exponent-pedometer.d.ts +10 -0
  58. package/build/core/native/exponent-pedometer.js +3 -0
  59. package/build/core/pedometer.d.ts +10 -0
  60. package/build/core/pedometer.js +44 -0
  61. package/build/react/hooks/use-accelerometer/index.d.ts +2 -0
  62. package/build/react/hooks/use-accelerometer/index.js +17 -0
  63. package/build/react/hooks/use-barometer/index.d.ts +2 -0
  64. package/build/react/hooks/use-barometer/index.js +17 -0
  65. package/build/react/hooks/use-device-motion/index.d.ts +2 -0
  66. package/build/react/hooks/use-device-motion/index.js +17 -0
  67. package/build/react/hooks/use-gyroscope/index.d.ts +2 -0
  68. package/build/react/hooks/use-gyroscope/index.js +17 -0
  69. package/build/react/hooks/use-light-sensor/index.d.ts +2 -0
  70. package/build/react/hooks/use-light-sensor/index.js +17 -0
  71. package/build/react/hooks/use-magnetometer/index.d.ts +2 -0
  72. package/build/react/hooks/use-magnetometer/index.js +17 -0
  73. package/build/react/hooks/use-magnetometer-uncalibrated/index.d.ts +2 -0
  74. package/build/react/hooks/use-magnetometer-uncalibrated/index.js +17 -0
  75. package/build/react/hooks/use-pedometer/index.d.ts +2 -0
  76. package/build/react/hooks/use-pedometer/index.js +14 -0
  77. package/build/react/index.d.ts +16 -0
  78. package/build/react/index.js +14 -0
  79. package/build/vue/composables/use-accelerometer/index.d.ts +3 -0
  80. package/build/vue/composables/use-accelerometer/index.js +25 -0
  81. package/build/vue/composables/use-barometer/index.d.ts +3 -0
  82. package/build/vue/composables/use-barometer/index.js +25 -0
  83. package/build/vue/composables/use-device-motion/index.d.ts +3 -0
  84. package/build/vue/composables/use-device-motion/index.js +25 -0
  85. package/build/vue/composables/use-gyroscope/index.d.ts +3 -0
  86. package/build/vue/composables/use-gyroscope/index.js +25 -0
  87. package/build/vue/composables/use-light-sensor/index.d.ts +3 -0
  88. package/build/vue/composables/use-light-sensor/index.js +25 -0
  89. package/build/vue/composables/use-magnetometer/index.d.ts +3 -0
  90. package/build/vue/composables/use-magnetometer/index.js +25 -0
  91. package/build/vue/composables/use-magnetometer-uncalibrated/index.d.ts +3 -0
  92. package/build/vue/composables/use-magnetometer-uncalibrated/index.js +25 -0
  93. package/build/vue/composables/use-pedometer/index.d.ts +3 -0
  94. package/build/vue/composables/use-pedometer/index.js +20 -0
  95. package/build/vue/index.d.ts +16 -0
  96. package/build/vue/index.js +14 -0
  97. package/build-ngc/angular/index.d.ts +16 -0
  98. package/build-ngc/angular/index.js +13 -0
  99. package/build-ngc/angular/index.js.map +1 -0
  100. package/build-ngc/angular/services/accelerometer.service/index.d.ts +9 -0
  101. package/build-ngc/angular/services/accelerometer.service/index.js +40 -0
  102. package/build-ngc/angular/services/accelerometer.service/index.js.map +1 -0
  103. package/build-ngc/angular/services/barometer.service/index.d.ts +9 -0
  104. package/build-ngc/angular/services/barometer.service/index.js +40 -0
  105. package/build-ngc/angular/services/barometer.service/index.js.map +1 -0
  106. package/build-ngc/angular/services/device-motion.service/index.d.ts +9 -0
  107. package/build-ngc/angular/services/device-motion.service/index.js +40 -0
  108. package/build-ngc/angular/services/device-motion.service/index.js.map +1 -0
  109. package/build-ngc/angular/services/gyroscope.service/index.d.ts +9 -0
  110. package/build-ngc/angular/services/gyroscope.service/index.js +40 -0
  111. package/build-ngc/angular/services/gyroscope.service/index.js.map +1 -0
  112. package/build-ngc/angular/services/light-sensor.service/index.d.ts +9 -0
  113. package/build-ngc/angular/services/light-sensor.service/index.js +40 -0
  114. package/build-ngc/angular/services/light-sensor.service/index.js.map +1 -0
  115. package/build-ngc/angular/services/magnetometer-uncalibrated.service/index.d.ts +9 -0
  116. package/build-ngc/angular/services/magnetometer-uncalibrated.service/index.js +40 -0
  117. package/build-ngc/angular/services/magnetometer-uncalibrated.service/index.js.map +1 -0
  118. package/build-ngc/angular/services/magnetometer.service/index.d.ts +9 -0
  119. package/build-ngc/angular/services/magnetometer.service/index.js +40 -0
  120. package/build-ngc/angular/services/magnetometer.service/index.js.map +1 -0
  121. package/build-ngc/angular/services/pedometer.service/index.d.ts +9 -0
  122. package/build-ngc/angular/services/pedometer.service/index.js +35 -0
  123. package/build-ngc/angular/services/pedometer.service/index.js.map +1 -0
  124. package/build-ngc/core/accelerometer.d.ts +10 -0
  125. package/build-ngc/core/accelerometer.js +7 -0
  126. package/build-ngc/core/accelerometer.js.map +1 -0
  127. package/build-ngc/core/barometer.d.ts +9 -0
  128. package/build-ngc/core/barometer.js +7 -0
  129. package/build-ngc/core/barometer.js.map +1 -0
  130. package/build-ngc/core/device-motion.d.ts +40 -0
  131. package/build-ngc/core/device-motion.js +22 -0
  132. package/build-ngc/core/device-motion.js.map +1 -0
  133. package/build-ngc/core/device-sensor.d.ts +27 -0
  134. package/build-ngc/core/device-sensor.js +62 -0
  135. package/build-ngc/core/device-sensor.js.map +1 -0
  136. package/build-ngc/core/gyroscope.d.ts +10 -0
  137. package/build-ngc/core/gyroscope.js +7 -0
  138. package/build-ngc/core/gyroscope.js.map +1 -0
  139. package/build-ngc/core/index.d.ts +11 -0
  140. package/build-ngc/core/index.js +11 -0
  141. package/build-ngc/core/index.js.map +1 -0
  142. package/build-ngc/core/light-sensor.d.ts +8 -0
  143. package/build-ngc/core/light-sensor.js +7 -0
  144. package/build-ngc/core/light-sensor.js.map +1 -0
  145. package/build-ngc/core/magnetometer-uncalibrated.d.ts +10 -0
  146. package/build-ngc/core/magnetometer-uncalibrated.js +7 -0
  147. package/build-ngc/core/magnetometer-uncalibrated.js.map +1 -0
  148. package/build-ngc/core/magnetometer.d.ts +10 -0
  149. package/build-ngc/core/magnetometer.js +7 -0
  150. package/build-ngc/core/magnetometer.js.map +1 -0
  151. package/build-ngc/core/native/exponent-accelerometer.d.ts +3 -0
  152. package/build-ngc/core/native/exponent-accelerometer.js +4 -0
  153. package/build-ngc/core/native/exponent-accelerometer.js.map +1 -0
  154. package/build-ngc/core/native/exponent-barometer.d.ts +3 -0
  155. package/build-ngc/core/native/exponent-barometer.js +4 -0
  156. package/build-ngc/core/native/exponent-barometer.js.map +1 -0
  157. package/build-ngc/core/native/exponent-device-motion.d.ts +7 -0
  158. package/build-ngc/core/native/exponent-device-motion.js +4 -0
  159. package/build-ngc/core/native/exponent-device-motion.js.map +1 -0
  160. package/build-ngc/core/native/exponent-gyroscope.d.ts +3 -0
  161. package/build-ngc/core/native/exponent-gyroscope.js +4 -0
  162. package/build-ngc/core/native/exponent-gyroscope.js.map +1 -0
  163. package/build-ngc/core/native/exponent-light-sensor/index.android.d.ts +3 -0
  164. package/build-ngc/core/native/exponent-light-sensor/index.android.js +4 -0
  165. package/build-ngc/core/native/exponent-light-sensor/index.android.js.map +1 -0
  166. package/build-ngc/core/native/exponent-light-sensor/index.d.ts +1 -0
  167. package/build-ngc/core/native/exponent-light-sensor/index.ios.d.ts +3 -0
  168. package/build-ngc/core/native/exponent-light-sensor/index.ios.js +7 -0
  169. package/build-ngc/core/native/exponent-light-sensor/index.ios.js.map +1 -0
  170. package/build-ngc/core/native/exponent-light-sensor/index.js +6 -0
  171. package/build-ngc/core/native/exponent-light-sensor/index.js.map +1 -0
  172. package/build-ngc/core/native/exponent-magnetometer-uncalibrated.d.ts +3 -0
  173. package/build-ngc/core/native/exponent-magnetometer-uncalibrated.js +4 -0
  174. package/build-ngc/core/native/exponent-magnetometer-uncalibrated.js.map +1 -0
  175. package/build-ngc/core/native/exponent-magnetometer.d.ts +3 -0
  176. package/build-ngc/core/native/exponent-magnetometer.js +4 -0
  177. package/build-ngc/core/native/exponent-magnetometer.js.map +1 -0
  178. package/build-ngc/core/native/exponent-pedometer.d.ts +10 -0
  179. package/build-ngc/core/native/exponent-pedometer.js +4 -0
  180. package/build-ngc/core/native/exponent-pedometer.js.map +1 -0
  181. package/build-ngc/core/pedometer.d.ts +10 -0
  182. package/build-ngc/core/pedometer.js +45 -0
  183. package/build-ngc/core/pedometer.js.map +1 -0
  184. package/package.json +106 -0
  185. package/src/angular/index.ts +26 -0
  186. package/src/angular/services/accelerometer.service/accelerometer.service.test.ts +118 -0
  187. package/src/angular/services/accelerometer.service/index.ts +39 -0
  188. package/src/angular/services/barometer.service/barometer.service.test.ts +122 -0
  189. package/src/angular/services/barometer.service/index.ts +39 -0
  190. package/src/angular/services/device-motion.service/device-motion.service.test.ts +125 -0
  191. package/src/angular/services/device-motion.service/index.ts +39 -0
  192. package/src/angular/services/gyroscope.service/gyroscope.service.test.ts +118 -0
  193. package/src/angular/services/gyroscope.service/index.ts +39 -0
  194. package/src/angular/services/light-sensor.service/index.ts +39 -0
  195. package/src/angular/services/light-sensor.service/light-sensor.service.test.ts +118 -0
  196. package/src/angular/services/magnetometer-uncalibrated.service/index.ts +39 -0
  197. package/src/angular/services/magnetometer-uncalibrated.service/magnetometer-uncalibrated.service.test.ts +123 -0
  198. package/src/angular/services/magnetometer.service/index.ts +39 -0
  199. package/src/angular/services/magnetometer.service/magnetometer.service.test.ts +118 -0
  200. package/src/angular/services/pedometer.service/index.ts +34 -0
  201. package/src/angular/services/pedometer.service/pedometer.service.test.ts +86 -0
  202. package/src/core/accelerometer.test.ts +49 -0
  203. package/src/core/accelerometer.ts +19 -0
  204. package/src/core/barometer.test.ts +46 -0
  205. package/src/core/barometer.ts +15 -0
  206. package/src/core/device-motion.test.ts +60 -0
  207. package/src/core/device-motion.ts +41 -0
  208. package/src/core/device-sensor.test.ts +76 -0
  209. package/src/core/device-sensor.ts +95 -0
  210. package/src/core/gyroscope.test.ts +46 -0
  211. package/src/core/gyroscope.ts +16 -0
  212. package/src/core/index.ts +37 -0
  213. package/src/core/light-sensor.test.ts +49 -0
  214. package/src/core/light-sensor.ts +18 -0
  215. package/src/core/magnetometer-uncalibrated.test.ts +49 -0
  216. package/src/core/magnetometer-uncalibrated.ts +20 -0
  217. package/src/core/magnetometer.test.ts +49 -0
  218. package/src/core/magnetometer.ts +19 -0
  219. package/src/core/native/exponent-accelerometer.ts +9 -0
  220. package/src/core/native/exponent-barometer.ts +9 -0
  221. package/src/core/native/exponent-device-motion.ts +15 -0
  222. package/src/core/native/exponent-gyroscope.ts +9 -0
  223. package/src/core/native/exponent-light-sensor/index.android.ts +9 -0
  224. package/src/core/native/exponent-light-sensor/index.ios.ts +12 -0
  225. package/src/core/native/exponent-light-sensor/index.ts +5 -0
  226. package/src/core/native/exponent-magnetometer-uncalibrated.ts +9 -0
  227. package/src/core/native/exponent-magnetometer.ts +9 -0
  228. package/src/core/native/exponent-pedometer.ts +17 -0
  229. package/src/core/pedometer.test.ts +118 -0
  230. package/src/core/pedometer.ts +62 -0
  231. package/src/react/hooks/use-accelerometer/index.ts +21 -0
  232. package/src/react/hooks/use-accelerometer/use-accelerometer.test.tsx +81 -0
  233. package/src/react/hooks/use-barometer/index.ts +21 -0
  234. package/src/react/hooks/use-barometer/use-barometer.test.tsx +83 -0
  235. package/src/react/hooks/use-device-motion/index.ts +21 -0
  236. package/src/react/hooks/use-device-motion/use-device-motion.test.tsx +88 -0
  237. package/src/react/hooks/use-gyroscope/index.ts +21 -0
  238. package/src/react/hooks/use-gyroscope/use-gyroscope.test.tsx +79 -0
  239. package/src/react/hooks/use-light-sensor/index.ts +21 -0
  240. package/src/react/hooks/use-light-sensor/use-light-sensor.test.tsx +79 -0
  241. package/src/react/hooks/use-magnetometer/index.ts +21 -0
  242. package/src/react/hooks/use-magnetometer/use-magnetometer.test.tsx +81 -0
  243. package/src/react/hooks/use-magnetometer-uncalibrated/index.ts +23 -0
  244. package/src/react/hooks/use-magnetometer-uncalibrated/use-magnetometer-uncalibrated.test.tsx +88 -0
  245. package/src/react/hooks/use-pedometer/index.ts +17 -0
  246. package/src/react/hooks/use-pedometer/use-pedometer.test.tsx +69 -0
  247. package/src/react/index.ts +29 -0
  248. package/src/vue/composables/use-accelerometer/index.ts +34 -0
  249. package/src/vue/composables/use-accelerometer/use-accelerometer.test.ts +96 -0
  250. package/src/vue/composables/use-barometer/index.ts +30 -0
  251. package/src/vue/composables/use-barometer/use-barometer.test.ts +100 -0
  252. package/src/vue/composables/use-device-motion/index.ts +30 -0
  253. package/src/vue/composables/use-device-motion/use-device-motion.test.ts +104 -0
  254. package/src/vue/composables/use-gyroscope/index.ts +30 -0
  255. package/src/vue/composables/use-gyroscope/use-gyroscope.test.ts +96 -0
  256. package/src/vue/composables/use-light-sensor/index.ts +30 -0
  257. package/src/vue/composables/use-light-sensor/use-light-sensor.test.ts +96 -0
  258. package/src/vue/composables/use-magnetometer/index.ts +30 -0
  259. package/src/vue/composables/use-magnetometer/use-magnetometer.test.ts +96 -0
  260. package/src/vue/composables/use-magnetometer-uncalibrated/index.ts +36 -0
  261. package/src/vue/composables/use-magnetometer-uncalibrated/use-magnetometer-uncalibrated.test.ts +103 -0
  262. package/src/vue/composables/use-pedometer/index.ts +25 -0
  263. package/src/vue/composables/use-pedometer/use-pedometer.test.ts +77 -0
  264. package/src/vue/index.ts +29 -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/sensors
2
+
3
+ A wrapper package for [SymbioteNative](../../README.md) that makes
4
+ [`expo-sensors`](https://github.com/expo/expo/tree/main/packages/expo-sensors) — Accelerometer,
5
+ Barometer, DeviceMotion, Gyroscope, LightSensor, Magnetometer, MagnetometerUncalibrated, and
6
+ Pedometer — usable from **every** adapter, React, Vue, and Angular. Unlike this repo's other
7
+ wrappers ([`@symbiote-native/slider`](../slider), [`@symbiote-native/navigation`](../navigation),
8
+ [`@symbiote-native/splash-screen`](../splash-screen)), `expo-sensors` isn't a plain RN native
9
+ module or view — it's built on `expo-modules-core`, so its native code autolinks straight out of
10
+ `node_modules` via `expo-modules-autolinking`, no proxy `react-native.config.cjs`/podspec to ship.
11
+ `expo-sensors`' own JS is never imported (it hard-imports the full `expo` meta-package, which this
12
+ project never depends on) — every sensor's logic is hand-ported into this package's own `core/`.
13
+
14
+ ## Install
15
+
16
+ ```bash
17
+ npm install @symbiote-native/sensors
18
+ ```
19
+
20
+ Depends on `expo-sensors` and `expo-modules-core` directly (regular dependencies, pinned to exact
21
+ versions — never a caret range, since this package's `core/` is hand-ported against one specific
22
+ native API shape and a newer resolve could silently drift the two apart). Never install
23
+ `expo-sensors` yourself, and never add the `expo` package to this project.
24
+
25
+ ## Required one-time step: native autolinking wiring
26
+
27
+ Unlike a plain RN native module, `expo-sensors`' native code is discovered by
28
+ `expo-modules-autolinking`, not RN's own `react-native.config.cjs` mechanism — this needs wiring
29
+ into the native host app **once**, covering this package and every future `expo-modules-core`
30
+ package with zero further changes:
31
+
32
+ | Platform | Touches |
33
+ |---|---|
34
+ | iOS | `ios/Podfile` — add `use_expo_modules!` |
35
+ | iOS | `AppDelegate.swift` — Expo's runtime-bootstrap hook |
36
+ | Android | `settings.gradle` / `app/build.gradle` — resolve and include the Expo Gradle projects |
37
+ | 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) |
38
+
39
+ Full mechanics — the Podfile pieces that normally ship inside the `expo` package, the `expo`
40
+ peer-dependency exclusion list, per-sensor permission strings — live in the
41
+ `symbiote-expo-native-module` skill. Reference implementation: `.examples/react/ios/Podfile` and
42
+ `.examples/react/android/app/src/main/java/com/canary/MainApplication.kt`.
43
+
44
+ Permissions ship with the native module itself — nothing to reimplement, just the platform
45
+ permission string each sensor needs (e.g. DeviceMotion/Pedometer need `NSMotionUsageDescription`
46
+ on iOS).
47
+
48
+ ## Shape
49
+
50
+ ```
51
+ src/core/ DeviceSensor base class + one class per sensor (Accelerometer, Barometer,
52
+ DeviceMotion, Gyroscope, LightSensor, Magnetometer,
53
+ MagnetometerUncalibrated); Pedometer is free functions instead — upstream
54
+ has no shared instance for it. native/ resolves each sensor's native
55
+ module by name through expo-modules-core's requireNativeModule.
56
+ src/react/hooks/ @symbiote-native/sensors/react — useAccelerometer, useBarometer, ...
57
+ src/vue/composables/ @symbiote-native/sensors/vue — useAccelerometer, useBarometer, ... (same names)
58
+ src/angular/services/ @symbiote-native/sensors/angular — AccelerometerService, BarometerService, ...
59
+ ```
60
+
61
+ Each adapter's hook/composable/service is a thin lifecycle wrapper (subscribe on mount, unsubscribe
62
+ on unmount) over the same `core` singleton — the subscription, permission, and update-interval
63
+ logic is written once and shared by all three.
64
+
65
+ ## Use it
66
+
67
+ ### A `DeviceSensor`-shaped sensor (Accelerometer, Barometer, DeviceMotion, Gyroscope, LightSensor, Magnetometer, MagnetometerUncalibrated)
68
+
69
+ ```tsx
70
+ // React
71
+ import { useAccelerometer } from '@symbiote-native/sensors/react';
72
+
73
+ function SensorsScreen() {
74
+ const accelerometer = useAccelerometer();
75
+ return <Text>{accelerometer && `x ${accelerometer.x} · y ${accelerometer.y} · z ${accelerometer.z}`}</Text>;
76
+ }
77
+ ```
78
+
79
+ ```vue
80
+ <!-- Vue -->
81
+ <script setup lang="ts">
82
+ import { useAccelerometer } from '@symbiote-native/sensors/vue';
83
+
84
+ const accelerometer = useAccelerometer();
85
+ </script>
86
+ <template>
87
+ <Text>{{ accelerometer && `x ${accelerometer.x} · y ${accelerometer.y} · z ${accelerometer.z}` }}</Text>
88
+ </template>
89
+ ```
90
+
91
+ ```ts
92
+ // Angular
93
+ import { Component, inject } from '@angular/core';
94
+ import { AccelerometerService } from '@symbiote-native/sensors/angular';
95
+
96
+ @Component({ /* ... */ })
97
+ export class SensorsScreen {
98
+ readonly accelerometer = inject(AccelerometerService).connect();
99
+ }
100
+ ```
101
+
102
+ The React example above mirrors the real demo screen, `.examples/react/screens/SensorsScreen.tsx`
103
+ — the Vue and Angular snippets are illustrative; those adapters' own demo screens aren't wired up
104
+ yet (React is this repo's "prove the pattern first" adapter for this package).
105
+
106
+ Every hook/composable/`connect()` takes an optional `updateIntervalMs` and returns `null` until the
107
+ first native reading arrives — check `isAvailableAsync()` separately if you need to distinguish
108
+ "not available on this device" from "no reading yet" (see [Notes](#notes) below).
109
+
110
+ ### Pedometer — free functions, no shared instance
111
+
112
+ ```ts
113
+ import { watchStepCount, getStepCountAsync, isAvailableAsync } from '@symbiote-native/sensors';
114
+ import { usePedometer } from '@symbiote-native/sensors/react'; // or /vue, /angular's PedometerService
115
+
116
+ const pedometer = usePedometer(); // { steps: number } | null, live-subscribed
117
+ const { steps } = await getStepCountAsync(startDate, endDate); // one-shot, iOS only in practice
118
+ ```
119
+
120
+ ## Notes
121
+
122
+ - **Simulators have no real IMU/pedometer hardware.** `isAvailableAsync()` genuinely returns
123
+ `false` on an iOS Simulator (every CoreMotion-backed sensor and `CMPedometer`); on an Android
124
+ emulator, readings drift on their own even at rest, since the emulator synthesizes motion data
125
+ rather than returning frozen zeros. Neither is a wiring bug; verify on a real device.
126
+ - **`DeviceMotion.rotation`/`.acceleration`/`.accelerationIncludingGravity`/`.rotationRate` are
127
+ nested and may be absent from the very first event** (the underlying sensor hasn't reported yet)
128
+ — guard the nested field itself (`deviceMotion?.rotation && ...`), not just the top-level object.
129
+ - **`rotation.beta` can read `NaN` near pitch ±90°** — an inherent Euler-angle gimbal-lock
130
+ singularity in `CMAttitude`/the platform's device-orientation math (the same one
131
+ `DeviceOrientationEvent.beta` has on the web), not a bug in this package.
132
+
133
+ ## Test it
134
+
135
+ No Fabric/Descriptor angle at all — a sensor is a pure `EventEmitter` + async-function surface,
136
+ never a view. Tests inject a fake native-module object in place of the real
137
+ `requireNativeModule` resolution (`src/core/**/*.test.ts`, `src/{react,vue,angular}/**/*.test.{ts,tsx}`),
138
+ the same pattern `expo-sensors` itself uses upstream — no `installFabric()`, no ViewConfig.
@@ -0,0 +1,16 @@
1
+ export { AccelerometerService } from './services/accelerometer.service';
2
+ export type { IAccelerometerMeasurement } from '../core';
3
+ export { BarometerService } from './services/barometer.service';
4
+ export type { IBarometerMeasurement } from '../core';
5
+ export { DeviceMotionService } from './services/device-motion.service';
6
+ export { DeviceMotionOrientation, gravity, type IDeviceMotionMeasurement } from '../core';
7
+ export { GyroscopeService } from './services/gyroscope.service';
8
+ export type { IGyroscopeMeasurement } from '../core';
9
+ export { LightSensorService } from './services/light-sensor.service';
10
+ export type { ILightSensorMeasurement } from '../core';
11
+ export { MagnetometerService } from './services/magnetometer.service';
12
+ export type { IMagnetometerMeasurement } from '../core';
13
+ export { MagnetometerUncalibratedService } from './services/magnetometer-uncalibrated.service';
14
+ export type { IMagnetometerUncalibratedMeasurement } from '../core';
15
+ export { PedometerService } from './services/pedometer.service';
16
+ export { watchStepCount, getStepCountAsync, isAvailableAsync, getPermissionsAsync, requestPermissionsAsync, type IPedometerResult, type IPedometerUpdateCallback, } from '../core';
@@ -0,0 +1,12 @@
1
+ // AccelerometerService is the Angular-only lifecycle half; the sensor singleton and event
2
+ // subscription plumbing all live in core, shared with React/Vue.
3
+ export { AccelerometerService } from './services/accelerometer.service/index.js';
4
+ export { BarometerService } from './services/barometer.service/index.js';
5
+ export { DeviceMotionService } from './services/device-motion.service/index.js';
6
+ export { DeviceMotionOrientation, gravity } from '../core/index.js';
7
+ export { GyroscopeService } from './services/gyroscope.service/index.js';
8
+ export { LightSensorService } from './services/light-sensor.service/index.js';
9
+ export { MagnetometerService } from './services/magnetometer.service/index.js';
10
+ export { MagnetometerUncalibratedService } from './services/magnetometer-uncalibrated.service/index.js';
11
+ export { PedometerService } from './services/pedometer.service/index.js';
12
+ export { watchStepCount, getStepCountAsync, isAvailableAsync, getPermissionsAsync, requestPermissionsAsync, } from '../core/index.js';
@@ -0,0 +1,6 @@
1
+ import { type Signal } from '@angular/core';
2
+ import { type IAccelerometerMeasurement } from '../../../core';
3
+ export declare class AccelerometerService {
4
+ private readonly injector;
5
+ connect(updateIntervalMs?: number): Signal<IAccelerometerMeasurement | null>;
6
+ }
@@ -0,0 +1,81 @@
1
+ var __esDecorate = (this && this.__esDecorate) || function (ctor, descriptorIn, decorators, contextIn, initializers, extraInitializers) {
2
+ function accept(f) { if (f !== void 0 && typeof f !== "function") throw new TypeError("Function expected"); return f; }
3
+ var kind = contextIn.kind, key = kind === "getter" ? "get" : kind === "setter" ? "set" : "value";
4
+ var target = !descriptorIn && ctor ? contextIn["static"] ? ctor : ctor.prototype : null;
5
+ var descriptor = descriptorIn || (target ? Object.getOwnPropertyDescriptor(target, contextIn.name) : {});
6
+ var _, done = false;
7
+ for (var i = decorators.length - 1; i >= 0; i--) {
8
+ var context = {};
9
+ for (var p in contextIn) context[p] = p === "access" ? {} : contextIn[p];
10
+ for (var p in contextIn.access) context.access[p] = contextIn.access[p];
11
+ context.addInitializer = function (f) { if (done) throw new TypeError("Cannot add initializers after decoration has completed"); extraInitializers.push(accept(f || null)); };
12
+ var result = (0, decorators[i])(kind === "accessor" ? { get: descriptor.get, set: descriptor.set } : descriptor[key], context);
13
+ if (kind === "accessor") {
14
+ if (result === void 0) continue;
15
+ if (result === null || typeof result !== "object") throw new TypeError("Object expected");
16
+ if (_ = accept(result.get)) descriptor.get = _;
17
+ if (_ = accept(result.set)) descriptor.set = _;
18
+ if (_ = accept(result.init)) initializers.unshift(_);
19
+ }
20
+ else if (_ = accept(result)) {
21
+ if (kind === "field") initializers.unshift(_);
22
+ else descriptor[key] = _;
23
+ }
24
+ }
25
+ if (target) Object.defineProperty(target, contextIn.name, descriptor);
26
+ done = true;
27
+ };
28
+ var __runInitializers = (this && this.__runInitializers) || function (thisArg, initializers, value) {
29
+ var useValue = arguments.length > 2;
30
+ for (var i = 0; i < initializers.length; i++) {
31
+ value = useValue ? initializers[i].call(thisArg, value) : initializers[i].call(thisArg);
32
+ }
33
+ return useValue ? value : void 0;
34
+ };
35
+ import { effect, inject, Injectable, Injector, signal } from '@angular/core';
36
+ import { Accelerometer } from '../../../core/index.js';
37
+ // Angular twin of React's `useAccelerometer` hook and Vue's `useAccelerometer` composable.
38
+ // Angular has no per-instance hook — state and lifecycle live in DI instead, so `connect()`
39
+ // stands in for the hook's role: call it ONCE (typically from a component's field initializer,
40
+ // inside an injection context).
41
+ //
42
+ // readonly measurement = inject(AccelerometerService).connect();
43
+ // // template: {{ measurement()?.x }}
44
+ //
45
+ // Unlike HideAnimationService.connect(), there is no per-render config to re-sync — the
46
+ // subscription doesn't depend on anything the caller's own signals could change between
47
+ // renders — so a single effect() that subscribes once and cleans up once is enough; no
48
+ // `updateConfig`-style effect that re-runs on every read is needed here.
49
+ let AccelerometerService = (() => {
50
+ let _classDecorators = [Injectable({ providedIn: 'root' })];
51
+ let _classDescriptor;
52
+ let _classExtraInitializers = [];
53
+ let _classThis;
54
+ var AccelerometerService = class {
55
+ static { _classThis = this; }
56
+ static {
57
+ const _metadata = typeof Symbol === "function" && Symbol.metadata ? Object.create(null) : void 0;
58
+ __esDecorate(null, _classDescriptor = { value: _classThis }, _classDecorators, { kind: "class", name: _classThis.name, metadata: _metadata }, null, _classExtraInitializers);
59
+ AccelerometerService = _classThis = _classDescriptor.value;
60
+ if (_metadata) Object.defineProperty(_classThis, Symbol.metadata, { enumerable: true, configurable: true, writable: true, value: _metadata });
61
+ __runInitializers(_classThis, _classExtraInitializers);
62
+ }
63
+ // Captured in the constructor (itself always run inside an injection context by Angular's
64
+ // own DI) so `connect()` can create an `effect()` even when called from plain field-initializer
65
+ // code that is not, on its own, an active injection context — mirrors HideAnimationService.
66
+ injector = inject(Injector);
67
+ connect(updateIntervalMs) {
68
+ const measurement = signal(null);
69
+ effect(onCleanup => {
70
+ if (updateIntervalMs !== undefined) {
71
+ Accelerometer.setUpdateInterval(updateIntervalMs);
72
+ }
73
+ const subscription = Accelerometer.addListener(next => measurement.set(next));
74
+ onCleanup(() => subscription.remove());
75
+ }, { injector: this.injector });
76
+ return measurement.asReadonly();
77
+ }
78
+ };
79
+ return AccelerometerService = _classThis;
80
+ })();
81
+ export { AccelerometerService };
@@ -0,0 +1,6 @@
1
+ import { type Signal } from '@angular/core';
2
+ import { type IBarometerMeasurement } from '../../../core';
3
+ export declare class BarometerService {
4
+ private readonly injector;
5
+ connect(updateIntervalMs?: number): Signal<IBarometerMeasurement | null>;
6
+ }
@@ -0,0 +1,81 @@
1
+ var __esDecorate = (this && this.__esDecorate) || function (ctor, descriptorIn, decorators, contextIn, initializers, extraInitializers) {
2
+ function accept(f) { if (f !== void 0 && typeof f !== "function") throw new TypeError("Function expected"); return f; }
3
+ var kind = contextIn.kind, key = kind === "getter" ? "get" : kind === "setter" ? "set" : "value";
4
+ var target = !descriptorIn && ctor ? contextIn["static"] ? ctor : ctor.prototype : null;
5
+ var descriptor = descriptorIn || (target ? Object.getOwnPropertyDescriptor(target, contextIn.name) : {});
6
+ var _, done = false;
7
+ for (var i = decorators.length - 1; i >= 0; i--) {
8
+ var context = {};
9
+ for (var p in contextIn) context[p] = p === "access" ? {} : contextIn[p];
10
+ for (var p in contextIn.access) context.access[p] = contextIn.access[p];
11
+ context.addInitializer = function (f) { if (done) throw new TypeError("Cannot add initializers after decoration has completed"); extraInitializers.push(accept(f || null)); };
12
+ var result = (0, decorators[i])(kind === "accessor" ? { get: descriptor.get, set: descriptor.set } : descriptor[key], context);
13
+ if (kind === "accessor") {
14
+ if (result === void 0) continue;
15
+ if (result === null || typeof result !== "object") throw new TypeError("Object expected");
16
+ if (_ = accept(result.get)) descriptor.get = _;
17
+ if (_ = accept(result.set)) descriptor.set = _;
18
+ if (_ = accept(result.init)) initializers.unshift(_);
19
+ }
20
+ else if (_ = accept(result)) {
21
+ if (kind === "field") initializers.unshift(_);
22
+ else descriptor[key] = _;
23
+ }
24
+ }
25
+ if (target) Object.defineProperty(target, contextIn.name, descriptor);
26
+ done = true;
27
+ };
28
+ var __runInitializers = (this && this.__runInitializers) || function (thisArg, initializers, value) {
29
+ var useValue = arguments.length > 2;
30
+ for (var i = 0; i < initializers.length; i++) {
31
+ value = useValue ? initializers[i].call(thisArg, value) : initializers[i].call(thisArg);
32
+ }
33
+ return useValue ? value : void 0;
34
+ };
35
+ import { effect, inject, Injectable, Injector, signal } from '@angular/core';
36
+ import { Barometer } from '../../../core/index.js';
37
+ // Angular twin of React's `useBarometer` hook and Vue's `useBarometer` composable.
38
+ // Angular has no per-instance hook — state and lifecycle live in DI instead, so `connect()`
39
+ // stands in for the hook's role: call it ONCE (typically from a component's field initializer,
40
+ // inside an injection context).
41
+ //
42
+ // readonly measurement = inject(BarometerService).connect();
43
+ // // template: {{ measurement()?.pressure }}
44
+ //
45
+ // Unlike HideAnimationService.connect(), there is no per-render config to re-sync — the
46
+ // subscription doesn't depend on anything the caller's own signals could change between
47
+ // renders — so a single effect() that subscribes once and cleans up once is enough; no
48
+ // `updateConfig`-style effect that re-runs on every read is needed here.
49
+ let BarometerService = (() => {
50
+ let _classDecorators = [Injectable({ providedIn: 'root' })];
51
+ let _classDescriptor;
52
+ let _classExtraInitializers = [];
53
+ let _classThis;
54
+ var BarometerService = class {
55
+ static { _classThis = this; }
56
+ static {
57
+ const _metadata = typeof Symbol === "function" && Symbol.metadata ? Object.create(null) : void 0;
58
+ __esDecorate(null, _classDescriptor = { value: _classThis }, _classDecorators, { kind: "class", name: _classThis.name, metadata: _metadata }, null, _classExtraInitializers);
59
+ BarometerService = _classThis = _classDescriptor.value;
60
+ if (_metadata) Object.defineProperty(_classThis, Symbol.metadata, { enumerable: true, configurable: true, writable: true, value: _metadata });
61
+ __runInitializers(_classThis, _classExtraInitializers);
62
+ }
63
+ // Captured in the constructor (itself always run inside an injection context by Angular's
64
+ // own DI) so `connect()` can create an `effect()` even when called from plain field-initializer
65
+ // code that is not, on its own, an active injection context — mirrors HideAnimationService.
66
+ injector = inject(Injector);
67
+ connect(updateIntervalMs) {
68
+ const measurement = signal(null);
69
+ effect(onCleanup => {
70
+ if (updateIntervalMs !== undefined) {
71
+ Barometer.setUpdateInterval(updateIntervalMs);
72
+ }
73
+ const subscription = Barometer.addListener(next => measurement.set(next));
74
+ onCleanup(() => subscription.remove());
75
+ }, { injector: this.injector });
76
+ return measurement.asReadonly();
77
+ }
78
+ };
79
+ return BarometerService = _classThis;
80
+ })();
81
+ export { BarometerService };
@@ -0,0 +1,6 @@
1
+ import { type Signal } from '@angular/core';
2
+ import { type IDeviceMotionMeasurement } from '../../../core';
3
+ export declare class DeviceMotionService {
4
+ private readonly injector;
5
+ connect(updateIntervalMs?: number): Signal<IDeviceMotionMeasurement | null>;
6
+ }
@@ -0,0 +1,81 @@
1
+ var __esDecorate = (this && this.__esDecorate) || function (ctor, descriptorIn, decorators, contextIn, initializers, extraInitializers) {
2
+ function accept(f) { if (f !== void 0 && typeof f !== "function") throw new TypeError("Function expected"); return f; }
3
+ var kind = contextIn.kind, key = kind === "getter" ? "get" : kind === "setter" ? "set" : "value";
4
+ var target = !descriptorIn && ctor ? contextIn["static"] ? ctor : ctor.prototype : null;
5
+ var descriptor = descriptorIn || (target ? Object.getOwnPropertyDescriptor(target, contextIn.name) : {});
6
+ var _, done = false;
7
+ for (var i = decorators.length - 1; i >= 0; i--) {
8
+ var context = {};
9
+ for (var p in contextIn) context[p] = p === "access" ? {} : contextIn[p];
10
+ for (var p in contextIn.access) context.access[p] = contextIn.access[p];
11
+ context.addInitializer = function (f) { if (done) throw new TypeError("Cannot add initializers after decoration has completed"); extraInitializers.push(accept(f || null)); };
12
+ var result = (0, decorators[i])(kind === "accessor" ? { get: descriptor.get, set: descriptor.set } : descriptor[key], context);
13
+ if (kind === "accessor") {
14
+ if (result === void 0) continue;
15
+ if (result === null || typeof result !== "object") throw new TypeError("Object expected");
16
+ if (_ = accept(result.get)) descriptor.get = _;
17
+ if (_ = accept(result.set)) descriptor.set = _;
18
+ if (_ = accept(result.init)) initializers.unshift(_);
19
+ }
20
+ else if (_ = accept(result)) {
21
+ if (kind === "field") initializers.unshift(_);
22
+ else descriptor[key] = _;
23
+ }
24
+ }
25
+ if (target) Object.defineProperty(target, contextIn.name, descriptor);
26
+ done = true;
27
+ };
28
+ var __runInitializers = (this && this.__runInitializers) || function (thisArg, initializers, value) {
29
+ var useValue = arguments.length > 2;
30
+ for (var i = 0; i < initializers.length; i++) {
31
+ value = useValue ? initializers[i].call(thisArg, value) : initializers[i].call(thisArg);
32
+ }
33
+ return useValue ? value : void 0;
34
+ };
35
+ import { effect, inject, Injectable, Injector, signal } from '@angular/core';
36
+ import { DeviceMotion } from '../../../core/index.js';
37
+ // Angular twin of React's `useDeviceMotion` hook and Vue's `useDeviceMotion` composable.
38
+ // Angular has no per-instance hook — state and lifecycle live in DI instead, so `connect()`
39
+ // stands in for the hook's role: call it ONCE (typically from a component's field initializer,
40
+ // inside an injection context).
41
+ //
42
+ // readonly measurement = inject(DeviceMotionService).connect();
43
+ // // template: {{ measurement()?.rotation?.alpha }}
44
+ //
45
+ // Unlike HideAnimationService.connect(), there is no per-render config to re-sync — the
46
+ // subscription doesn't depend on anything the caller's own signals could change between
47
+ // renders — so a single effect() that subscribes once and cleans up once is enough; no
48
+ // `updateConfig`-style effect that re-runs on every read is needed here.
49
+ let DeviceMotionService = (() => {
50
+ let _classDecorators = [Injectable({ providedIn: 'root' })];
51
+ let _classDescriptor;
52
+ let _classExtraInitializers = [];
53
+ let _classThis;
54
+ var DeviceMotionService = class {
55
+ static { _classThis = this; }
56
+ static {
57
+ const _metadata = typeof Symbol === "function" && Symbol.metadata ? Object.create(null) : void 0;
58
+ __esDecorate(null, _classDescriptor = { value: _classThis }, _classDecorators, { kind: "class", name: _classThis.name, metadata: _metadata }, null, _classExtraInitializers);
59
+ DeviceMotionService = _classThis = _classDescriptor.value;
60
+ if (_metadata) Object.defineProperty(_classThis, Symbol.metadata, { enumerable: true, configurable: true, writable: true, value: _metadata });
61
+ __runInitializers(_classThis, _classExtraInitializers);
62
+ }
63
+ // Captured in the constructor (itself always run inside an injection context by Angular's
64
+ // own DI) so `connect()` can create an `effect()` even when called from plain field-initializer
65
+ // code that is not, on its own, an active injection context — mirrors HideAnimationService.
66
+ injector = inject(Injector);
67
+ connect(updateIntervalMs) {
68
+ const measurement = signal(null);
69
+ effect(onCleanup => {
70
+ if (updateIntervalMs !== undefined) {
71
+ DeviceMotion.setUpdateInterval(updateIntervalMs);
72
+ }
73
+ const subscription = DeviceMotion.addListener(next => measurement.set(next));
74
+ onCleanup(() => subscription.remove());
75
+ }, { injector: this.injector });
76
+ return measurement.asReadonly();
77
+ }
78
+ };
79
+ return DeviceMotionService = _classThis;
80
+ })();
81
+ export { DeviceMotionService };
@@ -0,0 +1,6 @@
1
+ import { type Signal } from '@angular/core';
2
+ import { type IGyroscopeMeasurement } from '../../../core';
3
+ export declare class GyroscopeService {
4
+ private readonly injector;
5
+ connect(updateIntervalMs?: number): Signal<IGyroscopeMeasurement | null>;
6
+ }
@@ -0,0 +1,81 @@
1
+ var __esDecorate = (this && this.__esDecorate) || function (ctor, descriptorIn, decorators, contextIn, initializers, extraInitializers) {
2
+ function accept(f) { if (f !== void 0 && typeof f !== "function") throw new TypeError("Function expected"); return f; }
3
+ var kind = contextIn.kind, key = kind === "getter" ? "get" : kind === "setter" ? "set" : "value";
4
+ var target = !descriptorIn && ctor ? contextIn["static"] ? ctor : ctor.prototype : null;
5
+ var descriptor = descriptorIn || (target ? Object.getOwnPropertyDescriptor(target, contextIn.name) : {});
6
+ var _, done = false;
7
+ for (var i = decorators.length - 1; i >= 0; i--) {
8
+ var context = {};
9
+ for (var p in contextIn) context[p] = p === "access" ? {} : contextIn[p];
10
+ for (var p in contextIn.access) context.access[p] = contextIn.access[p];
11
+ context.addInitializer = function (f) { if (done) throw new TypeError("Cannot add initializers after decoration has completed"); extraInitializers.push(accept(f || null)); };
12
+ var result = (0, decorators[i])(kind === "accessor" ? { get: descriptor.get, set: descriptor.set } : descriptor[key], context);
13
+ if (kind === "accessor") {
14
+ if (result === void 0) continue;
15
+ if (result === null || typeof result !== "object") throw new TypeError("Object expected");
16
+ if (_ = accept(result.get)) descriptor.get = _;
17
+ if (_ = accept(result.set)) descriptor.set = _;
18
+ if (_ = accept(result.init)) initializers.unshift(_);
19
+ }
20
+ else if (_ = accept(result)) {
21
+ if (kind === "field") initializers.unshift(_);
22
+ else descriptor[key] = _;
23
+ }
24
+ }
25
+ if (target) Object.defineProperty(target, contextIn.name, descriptor);
26
+ done = true;
27
+ };
28
+ var __runInitializers = (this && this.__runInitializers) || function (thisArg, initializers, value) {
29
+ var useValue = arguments.length > 2;
30
+ for (var i = 0; i < initializers.length; i++) {
31
+ value = useValue ? initializers[i].call(thisArg, value) : initializers[i].call(thisArg);
32
+ }
33
+ return useValue ? value : void 0;
34
+ };
35
+ import { effect, inject, Injectable, Injector, signal } from '@angular/core';
36
+ import { Gyroscope } from '../../../core/index.js';
37
+ // Angular twin of React's `useGyroscope` hook and Vue's `useGyroscope` composable.
38
+ // Angular has no per-instance hook — state and lifecycle live in DI instead, so `connect()`
39
+ // stands in for the hook's role: call it ONCE (typically from a component's field initializer,
40
+ // inside an injection context).
41
+ //
42
+ // readonly measurement = inject(GyroscopeService).connect();
43
+ // // template: {{ measurement()?.x }}
44
+ //
45
+ // Unlike HideAnimationService.connect(), there is no per-render config to re-sync — the
46
+ // subscription doesn't depend on anything the caller's own signals could change between
47
+ // renders — so a single effect() that subscribes once and cleans up once is enough; no
48
+ // `updateConfig`-style effect that re-runs on every read is needed here.
49
+ let GyroscopeService = (() => {
50
+ let _classDecorators = [Injectable({ providedIn: 'root' })];
51
+ let _classDescriptor;
52
+ let _classExtraInitializers = [];
53
+ let _classThis;
54
+ var GyroscopeService = class {
55
+ static { _classThis = this; }
56
+ static {
57
+ const _metadata = typeof Symbol === "function" && Symbol.metadata ? Object.create(null) : void 0;
58
+ __esDecorate(null, _classDescriptor = { value: _classThis }, _classDecorators, { kind: "class", name: _classThis.name, metadata: _metadata }, null, _classExtraInitializers);
59
+ GyroscopeService = _classThis = _classDescriptor.value;
60
+ if (_metadata) Object.defineProperty(_classThis, Symbol.metadata, { enumerable: true, configurable: true, writable: true, value: _metadata });
61
+ __runInitializers(_classThis, _classExtraInitializers);
62
+ }
63
+ // Captured in the constructor (itself always run inside an injection context by Angular's
64
+ // own DI) so `connect()` can create an `effect()` even when called from plain field-initializer
65
+ // code that is not, on its own, an active injection context — mirrors HideAnimationService.
66
+ injector = inject(Injector);
67
+ connect(updateIntervalMs) {
68
+ const measurement = signal(null);
69
+ effect(onCleanup => {
70
+ if (updateIntervalMs !== undefined) {
71
+ Gyroscope.setUpdateInterval(updateIntervalMs);
72
+ }
73
+ const subscription = Gyroscope.addListener(next => measurement.set(next));
74
+ onCleanup(() => subscription.remove());
75
+ }, { injector: this.injector });
76
+ return measurement.asReadonly();
77
+ }
78
+ };
79
+ return GyroscopeService = _classThis;
80
+ })();
81
+ export { GyroscopeService };
@@ -0,0 +1,6 @@
1
+ import { type Signal } from '@angular/core';
2
+ import { type ILightSensorMeasurement } from '../../../core';
3
+ export declare class LightSensorService {
4
+ private readonly injector;
5
+ connect(updateIntervalMs?: number): Signal<ILightSensorMeasurement | null>;
6
+ }
@@ -0,0 +1,81 @@
1
+ var __esDecorate = (this && this.__esDecorate) || function (ctor, descriptorIn, decorators, contextIn, initializers, extraInitializers) {
2
+ function accept(f) { if (f !== void 0 && typeof f !== "function") throw new TypeError("Function expected"); return f; }
3
+ var kind = contextIn.kind, key = kind === "getter" ? "get" : kind === "setter" ? "set" : "value";
4
+ var target = !descriptorIn && ctor ? contextIn["static"] ? ctor : ctor.prototype : null;
5
+ var descriptor = descriptorIn || (target ? Object.getOwnPropertyDescriptor(target, contextIn.name) : {});
6
+ var _, done = false;
7
+ for (var i = decorators.length - 1; i >= 0; i--) {
8
+ var context = {};
9
+ for (var p in contextIn) context[p] = p === "access" ? {} : contextIn[p];
10
+ for (var p in contextIn.access) context.access[p] = contextIn.access[p];
11
+ context.addInitializer = function (f) { if (done) throw new TypeError("Cannot add initializers after decoration has completed"); extraInitializers.push(accept(f || null)); };
12
+ var result = (0, decorators[i])(kind === "accessor" ? { get: descriptor.get, set: descriptor.set } : descriptor[key], context);
13
+ if (kind === "accessor") {
14
+ if (result === void 0) continue;
15
+ if (result === null || typeof result !== "object") throw new TypeError("Object expected");
16
+ if (_ = accept(result.get)) descriptor.get = _;
17
+ if (_ = accept(result.set)) descriptor.set = _;
18
+ if (_ = accept(result.init)) initializers.unshift(_);
19
+ }
20
+ else if (_ = accept(result)) {
21
+ if (kind === "field") initializers.unshift(_);
22
+ else descriptor[key] = _;
23
+ }
24
+ }
25
+ if (target) Object.defineProperty(target, contextIn.name, descriptor);
26
+ done = true;
27
+ };
28
+ var __runInitializers = (this && this.__runInitializers) || function (thisArg, initializers, value) {
29
+ var useValue = arguments.length > 2;
30
+ for (var i = 0; i < initializers.length; i++) {
31
+ value = useValue ? initializers[i].call(thisArg, value) : initializers[i].call(thisArg);
32
+ }
33
+ return useValue ? value : void 0;
34
+ };
35
+ import { effect, inject, Injectable, Injector, signal } from '@angular/core';
36
+ import { LightSensor } from '../../../core/index.js';
37
+ // Angular twin of React's `useLightSensor` hook and Vue's `useLightSensor` composable.
38
+ // Angular has no per-instance hook — state and lifecycle live in DI instead, so `connect()`
39
+ // stands in for the hook's role: call it ONCE (typically from a component's field initializer,
40
+ // inside an injection context).
41
+ //
42
+ // readonly measurement = inject(LightSensorService).connect();
43
+ // // template: {{ measurement()?.illuminance }}
44
+ //
45
+ // Unlike HideAnimationService.connect(), there is no per-render config to re-sync — the
46
+ // subscription doesn't depend on anything the caller's own signals could change between
47
+ // renders — so a single effect() that subscribes once and cleans up once is enough; no
48
+ // `updateConfig`-style effect that re-runs on every read is needed here.
49
+ let LightSensorService = (() => {
50
+ let _classDecorators = [Injectable({ providedIn: 'root' })];
51
+ let _classDescriptor;
52
+ let _classExtraInitializers = [];
53
+ let _classThis;
54
+ var LightSensorService = class {
55
+ static { _classThis = this; }
56
+ static {
57
+ const _metadata = typeof Symbol === "function" && Symbol.metadata ? Object.create(null) : void 0;
58
+ __esDecorate(null, _classDescriptor = { value: _classThis }, _classDecorators, { kind: "class", name: _classThis.name, metadata: _metadata }, null, _classExtraInitializers);
59
+ LightSensorService = _classThis = _classDescriptor.value;
60
+ if (_metadata) Object.defineProperty(_classThis, Symbol.metadata, { enumerable: true, configurable: true, writable: true, value: _metadata });
61
+ __runInitializers(_classThis, _classExtraInitializers);
62
+ }
63
+ // Captured in the constructor (itself always run inside an injection context by Angular's
64
+ // own DI) so `connect()` can create an `effect()` even when called from plain field-initializer
65
+ // code that is not, on its own, an active injection context — mirrors HideAnimationService.
66
+ injector = inject(Injector);
67
+ connect(updateIntervalMs) {
68
+ const measurement = signal(null);
69
+ effect(onCleanup => {
70
+ if (updateIntervalMs !== undefined) {
71
+ LightSensor.setUpdateInterval(updateIntervalMs);
72
+ }
73
+ const subscription = LightSensor.addListener(next => measurement.set(next));
74
+ onCleanup(() => subscription.remove());
75
+ }, { injector: this.injector });
76
+ return measurement.asReadonly();
77
+ }
78
+ };
79
+ return LightSensorService = _classThis;
80
+ })();
81
+ export { LightSensorService };