react-native-nitro-compass 1.0.8 → 1.0.9

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 (2) hide show
  1. package/README.md +55 -2
  2. package/package.json +1 -1
package/README.md CHANGED
@@ -136,6 +136,7 @@ function CompassView() {
136
136
  filterDegrees: 1,
137
137
  declination: 0,
138
138
  pauseOnBackground: true,
139
+ enabled: true,
139
140
  })
140
141
 
141
142
  if (!hasCompass) return <Text>No compass on this device.</Text>
@@ -151,10 +152,62 @@ function CompassView() {
151
152
  }
152
153
  ```
153
154
 
154
- `filterDegrees`, `declination`, and `pauseOnBackground` are global state on `NitroCompass` — multiple hooks setting them are last-write-wins. Pass `enabled: false` to pause a hook's heading subscription without unmounting (calibration / interference observation continues).
155
+ ```ts
156
+ function useCompass(options?: UseCompassOptions): UseCompassResult
157
+ ```
158
+
159
+ #### Options
160
+
161
+ | Option | Type | Default | Description |
162
+ | --- | --- | --- | --- |
163
+ | `filterDegrees` | `number` | `1` | Minimum change between successive samples in degrees. Pass `0` for "every event". Updated live via `NitroCompass.setFilter()` whenever the prop changes. |
164
+ | `declination` | `number` | `0` | Magnetic-to-true offset in signed degrees. Pull from a model like [`geomagnetism`](https://github.com/kahirokunn/geomagnetism) keyed on the user's lat/lon. When non-zero, every emitted sample is true-north. |
165
+ | `pauseOnBackground` | `boolean` | `true` | Pause the underlying sensor / location-manager subscription while the app is backgrounded and resume on foreground. |
166
+ | `enabled` | `boolean` | `true` | Toggle the heading subscription without unmounting. When `false`, `reading` stops updating but calibration and interference observation continue (so you can still show warnings). |
167
+
168
+ `filterDegrees`, `declination`, and `pauseOnBackground` map to global state on `NitroCompass` — if multiple hooks set them, last-write-wins.
169
+
170
+ #### Result
171
+
172
+ | Field | Type | Description |
173
+ | --- | --- | --- |
174
+ | `reading` | `CompassSample \| null` | Latest emitted sample (`{ heading, accuracy }`), or `null` until the first arrives. Heading is true-north when `declination` is set, magnetic otherwise. |
175
+ | `quality` | `AccuracyQuality \| null` | Coarse calibration bucket — `'high'`, `'medium'`, `'low'`, or `'unreliable'`. `null` until the first transition. Show your own calibration UI on `'unreliable'`. |
176
+ | `interfering` | `boolean` | `true` while the raw magnetic field magnitude is outside the normal Earth band (~20–70 µT) — laptops, monitors, car engines, steel structures. |
177
+ | `hasCompass` | `boolean` | Hardware availability — read once on first render. Render a fallback when `false`. |
178
+ | `diagnostics` | `SensorDiagnostics \| undefined` | Which sensor backs the readings on this device (`rotationVector`, `geomagneticRotationVector`, or `coreLocation`). Useful for explaining quality differences. |
155
179
 
156
180
  For non-React state managers, lower-level `addHeadingListener(cb): () => void`, `addCalibrationListener(cb): () => void`, and `addInterferenceListener(cb): () => void` are also exported. They are reference-counted: the first heading listener calls `start()`, the last unsubscribe calls `stop()`. Mixing these helpers with direct `NitroCompass.start()` / `setOnCalibrationNeeded()` / `setOnInterferenceDetected()` will clobber the multiplex's internal callback slot — pick one path.
157
181
 
182
+ ### Smooth dial animation (Reanimated)
183
+
184
+ `useCompass()` returns React state, so each sample re-renders the consumer — fine for a numeric readout, but a rotating dial driven that way will jitter on faster filter values. For 60 fps animations, subscribe with `addHeadingListener` and write directly into a Reanimated shared value on the UI thread:
185
+
186
+ ```tsx
187
+ import Animated, { Easing, useAnimatedStyle, useSharedValue, withTiming } from 'react-native-reanimated'
188
+ import { addHeadingListener } from 'react-native-nitro-compass'
189
+
190
+ function Dial() {
191
+ const angle = useSharedValue(0)
192
+ const last = useRef(0)
193
+
194
+ useEffect(() => addHeadingListener(({ heading }) => {
195
+ // unwrap so 359° → 1° animates +2°, not -358°
196
+ const wrapped = ((last.current % 360) + 360) % 360
197
+ let delta = heading - wrapped
198
+ if (delta > 180) delta -= 360
199
+ else if (delta < -180) delta += 360
200
+ last.current += delta
201
+ angle.value = withTiming(last.current, { duration: 80, easing: Easing.out(Easing.quad) })
202
+ }), [angle])
203
+
204
+ const style = useAnimatedStyle(() => ({ transform: [{ rotate: `${-angle.value}deg` }] }))
205
+ return <Animated.View style={[styles.dial, style]}>{/* ticks */}</Animated.View>
206
+ }
207
+ ```
208
+
209
+ The same pattern is used in [example/components/Compass.tsx](./example/components/Compass.tsx).
210
+
158
211
  ## Permissions
159
212
 
160
213
  - **iOS**: requires `NSLocationWhenInUseUsageDescription` in `Info.plist`. `CLLocationManager` only emits headings when location permission is granted.
@@ -162,7 +215,7 @@ For non-React state managers, lower-level `addHeadingListener(cb): () => void`,
162
215
 
163
216
  ## Example app
164
217
 
165
- A bare React Native CLI app under [example/](./example) (RN 0.84.1, New Arch enabled) consumes the library via a local symlink. Use it to test changes on a real device — the iOS Simulator has no compass and the Android emulator's magnetometer is faked.
218
+ A bare React Native CLI app under [example/](./example) (RN 0.85.3, New Arch enabled) consumes the library via a local symlink. It demos the full surface — `useCompass()` for the readout, calibration / interference banners, and a Reanimated-driven dial that subscribes via `addHeadingListener` so the rotation runs entirely on the UI thread. Use it to test changes on a real device — the iOS Simulator has no compass and the Android emulator's magnetometer is faked.
166
219
 
167
220
  First-time setup:
168
221
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "react-native-nitro-compass",
3
- "version": "1.0.8",
3
+ "version": "1.0.9",
4
4
  "engines": {
5
5
  "node": ">=18"
6
6
  },