@symbiote-native/haptics 3.0.1 → 3.0.3
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 +38 -28
- package/package.json +15 -15
package/README.md
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
# @symbiote-native/haptics
|
|
2
2
|
|
|
3
3
|
Port of [`expo-haptics`](https://docs.expo.dev/versions/latest/sdk/haptics/) for
|
|
4
|
-
[SymbioteNative](../../README.md)
|
|
4
|
+
[SymbioteNative](../../README.md) - impact/notification/selection vibration feedback via iOS's
|
|
5
5
|
Taptic Engine and Android's Vibrator API, plus a direct Android haptics-engine path
|
|
6
6
|
(`performAndroidHapticsAsync`). Built the same way as
|
|
7
7
|
[`@symbiote-native/local-auth`](../local-auth): an `expo-modules-core`-based wrapper, free
|
|
8
|
-
functions with no per-instance state and no event stream. Reachable from every adapter
|
|
9
|
-
Vue, Svelte, Solid, Angular
|
|
8
|
+
functions with no per-instance state and no event stream. Reachable from every adapter - React,
|
|
9
|
+
Vue, Svelte, Solid, Angular - not just React.
|
|
10
10
|
|
|
11
11
|
## Install
|
|
12
12
|
|
|
@@ -22,40 +22,40 @@ npx @symbiote-native/cli new my-app --haptics
|
|
|
22
22
|
npx @symbiote-native/cli add --haptics
|
|
23
23
|
```
|
|
24
24
|
|
|
25
|
-
Either way: installs `@symbiote-native/haptics` and wires the native autolinking automatically
|
|
25
|
+
Either way: installs `@symbiote-native/haptics` and wires the native autolinking automatically,
|
|
26
26
|
see [`@symbiote-native/cli`](../cli).
|
|
27
27
|
|
|
28
28
|
<details>
|
|
29
|
-
<summary>Manual install (no CLI
|
|
29
|
+
<summary>Manual install (no CLI - installing and wiring native autolinking by hand)</summary>
|
|
30
30
|
|
|
31
31
|
```bash
|
|
32
32
|
npm install @symbiote-native/haptics
|
|
33
33
|
```
|
|
34
34
|
|
|
35
|
-
`expo-haptics` and `expo-modules-core` come along as regular, exact-pinned dependencies
|
|
35
|
+
`expo-haptics` and `expo-modules-core` come along as regular, exact-pinned dependencies - never
|
|
36
36
|
install either yourself, and never add the `expo` meta-package (it bundles its own Metro/Babel
|
|
37
37
|
pipeline that conflicts with this project's own).
|
|
38
38
|
|
|
39
39
|
### Required one-time step: native autolinking wiring
|
|
40
40
|
|
|
41
41
|
Unlike a plain RN native module, `expo-haptics`' native code is discovered by
|
|
42
|
-
`expo-modules-autolinking`, not RN's own `react-native.config.cjs`/podspec mechanism
|
|
42
|
+
`expo-modules-autolinking`, not RN's own `react-native.config.cjs`/podspec mechanism - this needs
|
|
43
43
|
wiring into the native host app **once**, covering this package and every other
|
|
44
44
|
`expo-modules-core` package with zero further changes:
|
|
45
45
|
|
|
46
46
|
| Platform | Touches |
|
|
47
47
|
| -------- | --------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
48
|
-
| iOS | `ios/Podfile`
|
|
49
|
-
| iOS | `AppDelegate.swift`
|
|
50
|
-
| Android | `settings.gradle` / `app/build.gradle`
|
|
51
|
-
| Android | `MainApplication.kt`
|
|
48
|
+
| iOS | `ios/Podfile` - add `use_expo_modules!` |
|
|
49
|
+
| iOS | `AppDelegate.swift` - Expo's runtime-bootstrap hook |
|
|
50
|
+
| Android | `settings.gradle` / `app/build.gradle` - resolve and include the Expo Gradle projects |
|
|
51
|
+
| 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) |
|
|
52
52
|
|
|
53
53
|
Full mechanics live in the `symbiote-expo-native-module` project skill. Reference
|
|
54
54
|
implementation: `examples/expo-react/ios/Podfile` and
|
|
55
55
|
`examples/expo-react/android/app/src/main/java/com/canaryexpo/MainApplication.kt` (registers
|
|
56
56
|
`HapticsModule` as `"ExpoHaptics"`).
|
|
57
57
|
|
|
58
|
-
No permission or `Info.plist`/`AndroidManifest.xml` entry is needed on either platform
|
|
58
|
+
No permission or `Info.plist`/`AndroidManifest.xml` entry is needed on either platform - haptic
|
|
59
59
|
feedback requires none.
|
|
60
60
|
|
|
61
61
|
</details>
|
|
@@ -67,10 +67,10 @@ src/core/ notificationAsync / impactAsync / selectionAsync / performAndroidH
|
|
|
67
67
|
plus NotificationFeedbackType / ImpactFeedbackStyle / AndroidHaptics.
|
|
68
68
|
native-module.ts resolves the ExpoHaptics native module via
|
|
69
69
|
expo-modules-core's requireNativeModule.
|
|
70
|
-
src/angular/ @symbiote-native/haptics/angular
|
|
70
|
+
src/angular/ @symbiote-native/haptics/angular - plain re-export of core.
|
|
71
71
|
```
|
|
72
72
|
|
|
73
|
-
Upstream ships four async functions and three enums, not a subscribable sensor
|
|
73
|
+
Upstream ships four async functions and three enums, not a subscribable sensor - there's
|
|
74
74
|
nothing per-framework to add, so `./react`, `./vue`, `./svelte`, and `./solid` are
|
|
75
75
|
`exports`-map aliases straight onto `src/core/` (no physical per-framework file). `./angular`
|
|
76
76
|
stays a physical file/subpath since Angular ships through a separate `ngc`/AOT build
|
|
@@ -79,7 +79,7 @@ stays a physical file/subpath since Angular ships through a separate `ngc`/AOT b
|
|
|
79
79
|
## Use it
|
|
80
80
|
|
|
81
81
|
```tsx
|
|
82
|
-
// React
|
|
82
|
+
// React - examples/expo-react/screens/HapticsScreen.tsx
|
|
83
83
|
import {
|
|
84
84
|
impactAsync,
|
|
85
85
|
ImpactFeedbackStyle,
|
|
@@ -106,7 +106,7 @@ function HapticsScreen() {
|
|
|
106
106
|
```
|
|
107
107
|
|
|
108
108
|
```vue
|
|
109
|
-
<!-- Vue
|
|
109
|
+
<!-- Vue - examples/expo-vue-sfc/screens/HapticsScreen.vue -->
|
|
110
110
|
<script setup lang="ts">
|
|
111
111
|
import {
|
|
112
112
|
impactAsync,
|
|
@@ -129,7 +129,7 @@ function fireImpact(style: ImpactFeedbackStyle): void {
|
|
|
129
129
|
```
|
|
130
130
|
|
|
131
131
|
```svelte
|
|
132
|
-
<!-- Svelte
|
|
132
|
+
<!-- Svelte - examples/expo-svelte/screens/HapticsScreen.svelte -->
|
|
133
133
|
<script lang="ts">
|
|
134
134
|
import {
|
|
135
135
|
impactAsync,
|
|
@@ -152,7 +152,7 @@ function fireImpact(style: ImpactFeedbackStyle): void {
|
|
|
152
152
|
```
|
|
153
153
|
|
|
154
154
|
```tsx
|
|
155
|
-
// Solid
|
|
155
|
+
// Solid - examples/expo-solid/screens/HapticsScreen.tsx
|
|
156
156
|
import {
|
|
157
157
|
impactAsync,
|
|
158
158
|
ImpactFeedbackStyle,
|
|
@@ -179,7 +179,7 @@ function HapticsScreen() {
|
|
|
179
179
|
```
|
|
180
180
|
|
|
181
181
|
```ts
|
|
182
|
-
// Angular
|
|
182
|
+
// Angular - examples/expo-angular/src/screens/HapticsScreen.ts
|
|
183
183
|
import { Component } from '@angular/core';
|
|
184
184
|
import {
|
|
185
185
|
impactAsync,
|
|
@@ -202,7 +202,7 @@ export class HapticsScreen {
|
|
|
202
202
|
}
|
|
203
203
|
```
|
|
204
204
|
|
|
205
|
-
Every call is fire-and-forget (no result to await)
|
|
205
|
+
Every call is fire-and-forget (no result to await) - a real device is needed to feel the
|
|
206
206
|
feedback, a simulator produces none. Android also gets `performAndroidHapticsAsync`, which
|
|
207
207
|
drives the device haptics engine directly instead of `impactAsync`'s Vibrator simulation; it
|
|
208
208
|
no-ops on every other platform.
|
|
@@ -213,24 +213,24 @@ Free functions, no event stream, no per-instance state:
|
|
|
213
213
|
|
|
214
214
|
```ts
|
|
215
215
|
notificationAsync(type?: NotificationFeedbackType): Promise<void>
|
|
216
|
-
// Success/Warning/Error feedback
|
|
216
|
+
// Success/Warning/Error feedback - UINotificationFeedbackType on iOS, simulated via Vibrator on Android.
|
|
217
217
|
|
|
218
218
|
impactAsync(style?: ImpactFeedbackStyle): Promise<void>
|
|
219
|
-
// Collision-weight feedback (Light/Medium/Heavy/Soft/Rigid)
|
|
219
|
+
// Collision-weight feedback (Light/Medium/Heavy/Soft/Rigid) - UIImpactFeedbackStyle on iOS, simulated via Vibrator on Android.
|
|
220
220
|
|
|
221
221
|
selectionAsync(): Promise<void>
|
|
222
222
|
// Lets the user know a selection change was registered.
|
|
223
223
|
|
|
224
224
|
performAndroidHapticsAsync(type: AndroidHaptics): Promise<void>
|
|
225
|
-
// Android only
|
|
225
|
+
// Android only - no-ops on other platforms. Uses the device haptics engine directly, unlike the Vibrator-based impactAsync.
|
|
226
226
|
```
|
|
227
227
|
|
|
228
|
-
Plus `NotificationFeedbackType`, `ImpactFeedbackStyle`, `AndroidHaptics`
|
|
228
|
+
Plus `NotificationFeedbackType`, `ImpactFeedbackStyle`, `AndroidHaptics` - ported verbatim from
|
|
229
229
|
upstream's `Haptics.types.ts`.
|
|
230
230
|
|
|
231
231
|
```ts
|
|
232
232
|
import { impactAsync, ImpactFeedbackStyle } from '@symbiote-native/haptics';
|
|
233
|
-
// or the framework-scoped entry points
|
|
233
|
+
// or the framework-scoped entry points - identical surface, re-exported verbatim:
|
|
234
234
|
import { impactAsync } from '@symbiote-native/haptics/react';
|
|
235
235
|
import { impactAsync } from '@symbiote-native/haptics/vue';
|
|
236
236
|
import { impactAsync } from '@symbiote-native/haptics/svelte';
|
|
@@ -238,17 +238,27 @@ import { impactAsync } from '@symbiote-native/haptics/solid';
|
|
|
238
238
|
import { impactAsync } from '@symbiote-native/haptics/angular';
|
|
239
239
|
```
|
|
240
240
|
|
|
241
|
+
## Common questions
|
|
242
|
+
|
|
243
|
+
- **Nothing on the iOS Simulator.** It never fires haptics; use a device.
|
|
244
|
+
- **Nothing on a real iPhone.** Low Power Mode, active camera or dictation, or system haptics off.
|
|
245
|
+
- **Silent in a standalone Android build.** Reported upstream; test a release build.
|
|
246
|
+
|
|
247
|
+
Sources: [Expo docs: Haptics](https://docs.expo.dev/versions/latest/sdk/haptics/),
|
|
248
|
+
[expo/expo#16218](https://github.com/expo/expo/issues/16218),
|
|
249
|
+
[expo/expo#6375](https://github.com/expo/expo/issues/6375).
|
|
250
|
+
|
|
241
251
|
## Test it
|
|
242
252
|
|
|
243
|
-
No Fabric/Descriptor angle at all
|
|
253
|
+
No Fabric/Descriptor angle at all - haptics is a pure async-function surface, never a view.
|
|
244
254
|
Tests exercise the JS layer via a fake native module in place of the real
|
|
245
|
-
`requireNativeModule` resolution (`vitest`, `src/**/*.test.{ts,tsx}`)
|
|
255
|
+
`requireNativeModule` resolution (`vitest`, `src/**/*.test.{ts,tsx}`) - no `installFabric()`, no
|
|
246
256
|
ViewConfig. Native rendering itself is verified on-device (see the parent
|
|
247
257
|
[README](../../README.md)).
|
|
248
258
|
|
|
249
259
|
Native wiring for this package is done across all six `examples/expo-*` canary apps (Android
|
|
250
260
|
3-layer registration in each app's `build.gradle`/`MainApplication.kt`/`AndroidManifest.xml`,
|
|
251
|
-
plus iOS Podfile/pod install)
|
|
261
|
+
plus iOS Podfile/pod install) - not yet ported into the plain, non-Expo public canaries
|
|
252
262
|
(`examples/react`, `examples/vue-sfc`, `examples/vue-tsx`, `examples/svelte`, `examples/solid`,
|
|
253
263
|
`examples/angular`), and no on-device/simulator automated (Detox) smoke test exists yet, only
|
|
254
264
|
manual verification.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@symbiote-native/haptics",
|
|
3
|
-
"version": "3.0.
|
|
3
|
+
"version": "3.0.3",
|
|
4
4
|
"description": "expo-haptics wrapped for SymbioteNative — one framework-agnostic core, built once and reachable from the React, Vue, Svelte, Solid, and Angular adapters. Impact/notification/selection vibration feedback via iOS's Taptic Engine and Android's Vibrator API.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": {
|
|
@@ -70,7 +70,7 @@
|
|
|
70
70
|
},
|
|
71
71
|
"dependencies": {
|
|
72
72
|
"expo-haptics": "57.0.1",
|
|
73
|
-
"expo-modules-core": "57.0.
|
|
73
|
+
"expo-modules-core": "57.0.20"
|
|
74
74
|
},
|
|
75
75
|
"peerDependencies": {
|
|
76
76
|
"@angular/core": ">=20",
|
|
@@ -80,12 +80,12 @@
|
|
|
80
80
|
"solid-js": ">=1.9.0",
|
|
81
81
|
"svelte": ">=5.56.0",
|
|
82
82
|
"vue": ">=3.5.0",
|
|
83
|
-
"@symbiote-native/angular": "^3.
|
|
84
|
-
"@symbiote-native/engine": "^1.
|
|
85
|
-
"@symbiote-native/react": "^3.0
|
|
86
|
-
"@symbiote-native/solid": "^3.0
|
|
87
|
-
"@symbiote-native/svelte": "^3.0
|
|
88
|
-
"@symbiote-native/vue": "^3.0
|
|
83
|
+
"@symbiote-native/angular": "^3.2.0",
|
|
84
|
+
"@symbiote-native/engine": "^1.5.0",
|
|
85
|
+
"@symbiote-native/react": "^3.2.0",
|
|
86
|
+
"@symbiote-native/solid": "^3.1.0",
|
|
87
|
+
"@symbiote-native/svelte": "^3.1.0",
|
|
88
|
+
"@symbiote-native/vue": "^3.2.0"
|
|
89
89
|
},
|
|
90
90
|
"peerDependenciesMeta": {
|
|
91
91
|
"@symbiote-native/angular": {
|
|
@@ -133,13 +133,13 @@
|
|
|
133
133
|
"solid-js": "^1.9.14",
|
|
134
134
|
"svelte": "^5.56.0",
|
|
135
135
|
"typescript": "~6.0.0",
|
|
136
|
-
"@symbiote-native/angular": "3.
|
|
137
|
-
"@symbiote-native/engine": "1.
|
|
138
|
-
"@symbiote-native/react": "3.0
|
|
139
|
-
"@symbiote-native/solid": "3.0
|
|
140
|
-
"@symbiote-native/svelte": "3.0
|
|
141
|
-
"@symbiote-native/test-utils": "0.4.
|
|
142
|
-
"@symbiote-native/vue": "3.0
|
|
136
|
+
"@symbiote-native/angular": "3.2.0",
|
|
137
|
+
"@symbiote-native/engine": "1.5.0",
|
|
138
|
+
"@symbiote-native/react": "3.2.0",
|
|
139
|
+
"@symbiote-native/solid": "3.1.0",
|
|
140
|
+
"@symbiote-native/svelte": "3.1.0",
|
|
141
|
+
"@symbiote-native/test-utils": "0.4.6",
|
|
142
|
+
"@symbiote-native/vue": "3.2.0"
|
|
143
143
|
},
|
|
144
144
|
"scripts": {
|
|
145
145
|
"typecheck": "tsc --build",
|