@userflow-tech/react-native 0.4.0 → 0.4.1
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 +90 -84
- package/docs/anchoring.md +3 -4
- package/docs/troubleshooting.md +1 -4
- package/lib/commonjs/version.js +1 -1
- package/lib/module/version.js +1 -1
- package/lib/typescript/commonjs/src/version.d.ts +1 -1
- package/lib/typescript/module/src/version.d.ts +1 -1
- package/package.json +1 -1
- package/src/version.ts +1 -1
- package/vendor/core/package.json +1 -1
- package/vendor/protocol/package.json +1 -1
- package/docs/theme-mapping.md +0 -130
package/README.md
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
# `@userflow-tech/react-native`
|
|
2
2
|
|
|
3
3
|
Official Userflow SDK for React Native and Expo. Deliver guided flows, tooltips,
|
|
4
|
-
and
|
|
5
|
-
release for every content change.
|
|
4
|
+
modals, and banners authored in the Userflow dashboard — without shipping a new
|
|
5
|
+
app release for every content change.
|
|
6
6
|
|
|
7
7
|
> Early development. APIs may change.
|
|
8
8
|
|
|
@@ -10,10 +10,9 @@ release for every content change.
|
|
|
10
10
|
|
|
11
11
|
Declared minimums: React `>=18.2.0`, React Native `>=0.76.0`. React Native
|
|
12
12
|
0.74 and 0.75 cannot install this SDK: `react-native-view-shot` 5.x, which
|
|
13
|
-
Builder element selection needs, requires React Native 0.76 or later.
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
not supported.
|
|
13
|
+
Builder element selection needs, requires React Native 0.76 or later. The SDK
|
|
14
|
+
is tested on React Native 0.81 / React 19.1 and on Expo SDK 57 / React Native
|
|
15
|
+
0.86. Expo Go is not supported.
|
|
17
16
|
|
|
18
17
|
`@react-native-async-storage/async-storage` is the only native module this
|
|
19
18
|
package depends on, so npm installs it. `react-native-webview` and
|
|
@@ -44,13 +43,9 @@ the ranges below.
|
|
|
44
43
|
Optional peers are declared `optional: true` in `peerDependenciesMeta`, so
|
|
45
44
|
package managers do not warn if you skip them.
|
|
46
45
|
|
|
47
|
-
npm
|
|
48
|
-
`react-native-
|
|
49
|
-
|
|
50
|
-
missing-peer warnings among unrelated ones. That is why the install commands
|
|
51
|
-
list WebView and view-shot explicitly. A clean npm install prints no warning
|
|
52
|
-
about optional peers, so install `react-native-safe-area-context` and NetInfo
|
|
53
|
-
yourself when you want the behavior in the table. An app that already depends
|
|
46
|
+
A clean npm install prints no warning about optional peers, so install
|
|
47
|
+
`react-native-safe-area-context` and NetInfo yourself when you want the behavior
|
|
48
|
+
in the table. An app that already depends
|
|
54
49
|
on an older major (view-shot 4.0.3, NetInfo 9.x, safe-area 3.x, WebView 13.6.x
|
|
55
50
|
or 14.x) fails install with `ERESOLVE`.
|
|
56
51
|
|
|
@@ -65,19 +60,8 @@ Use an **Expo development build** (or bare React Native). In development,
|
|
|
65
60
|
|
|
66
61
|
## Install
|
|
67
62
|
|
|
68
|
-
The package is public on npm
|
|
69
|
-
|
|
70
|
-
Yarn 2 and later ignore `.npmrc`. Add this to `.yarnrc.yml` instead:
|
|
71
|
-
|
|
72
|
-
```yaml
|
|
73
|
-
npmScopes:
|
|
74
|
-
userflow-tech:
|
|
75
|
-
npmRegistryServer: 'https://registry.npmjs.org'
|
|
76
|
-
npmAuthToken: '${NPM_TOKEN}'
|
|
77
|
-
```
|
|
78
|
-
|
|
79
|
-
Set `NPM_TOKEN` in the environment that installs dependencies: a local shell,
|
|
80
|
-
CI, and EAS (an EAS secret named `NPM_TOKEN`, available to the install step).
|
|
63
|
+
The package is public on npm. No token, `.npmrc`, or `.yarnrc.yml` setup is
|
|
64
|
+
needed with any package manager.
|
|
81
65
|
|
|
82
66
|
### Packages
|
|
83
67
|
|
|
@@ -130,10 +114,6 @@ npx expo install react-native-safe-area-context @react-native-community/netinfo
|
|
|
130
114
|
# and either expo-router or @react-navigation/native, depending on your router
|
|
131
115
|
```
|
|
132
116
|
|
|
133
|
-
For local tarball installs from this monorepo, pack with `pnpm pack:all` at the
|
|
134
|
-
repo root and install the single `@userflow-tech/react-native` tarball. Steps:
|
|
135
|
-
`docs/local-testing.md` in the monorepo.
|
|
136
|
-
|
|
137
117
|
### Install with an AI agent
|
|
138
118
|
|
|
139
119
|
Cursor, Claude Code, and other agents that read Agent Skills can do this
|
|
@@ -159,7 +139,7 @@ Claude Code loads it from the plugin:
|
|
|
159
139
|
import { Userflow, UserflowProvider } from '@userflow-tech/react-native';
|
|
160
140
|
|
|
161
141
|
await Userflow.init({
|
|
162
|
-
clientToken: 'ct_...', // from the Userflow dashboard
|
|
142
|
+
clientToken: 'ct_...', // from Settings → Environments in the Userflow dashboard. Never an esk_ secret key.
|
|
163
143
|
// serverEndpoint: 'https://e.userflow.com', // default (US). EU: 'https://e.eu.userflow.com'
|
|
164
144
|
// pairingEndpoint: 'https://e.userflow.com', // default; pairing stays on the US host
|
|
165
145
|
});
|
|
@@ -178,6 +158,17 @@ NetInfo subscriptions). Call `Userflow.reset()` on logout to clear identity and
|
|
|
178
158
|
disconnect. `reset()` does not apply a new `clientToken` or endpoint; restart
|
|
179
159
|
the app to change those.
|
|
180
160
|
|
|
161
|
+
### `init` options
|
|
162
|
+
|
|
163
|
+
| Option | Default | Description |
|
|
164
|
+
| ----------------- | ------------------------ | ------------------------------------------------------------------------------------------------------------ |
|
|
165
|
+
| `clientToken` | — | **Required.** The `ct_…` client token from Settings → Environments. |
|
|
166
|
+
| `serverEndpoint` | `https://e.userflow.com` | Userflow host. EU environments use `https://e.eu.userflow.com`. |
|
|
167
|
+
| `pairingEndpoint` | `https://e.userflow.com` | Builder pairing host. Stays on the US host for EU environments too. |
|
|
168
|
+
| `onNavigate` | — | Handler for flow NAVIGATE actions. Wins over React Navigation, Expo Router, and Linking. See NAVIGATE below. |
|
|
169
|
+
| `appVersion` | Read from the native app | Override the host app version sent as `app_version`. |
|
|
170
|
+
| `appBuild` | Read from the native app | Build number sent as `app_build`, paired with `appVersion`. |
|
|
171
|
+
|
|
181
172
|
### Where to put `init`, `identify`, and `UserflowProvider`
|
|
182
173
|
|
|
183
174
|
Call `Userflow.init` once, as early as you can, from the root component
|
|
@@ -247,14 +238,14 @@ to the device's initial insets:
|
|
|
247
238
|
|
|
248
239
|
### Call order
|
|
249
240
|
|
|
250
|
-
| Call | Before `init()` resolves | Before `identify()`
|
|
251
|
-
| -------------------------------- | ------------------------------------------------------ |
|
|
252
|
-
| `identify` / `identifyAnonymous` | **Throws** `Call Userflow.init() before identify()` | —
|
|
253
|
-
| `group` | **Throws** `Call Userflow.init() before group()` | **Throws** `Call Userflow.identify() before group()`
|
|
254
|
-
| `updateUser` | **Throws** `Call Userflow.init() before updateUser()` | **Throws** `Call Userflow.identify() before updateUser()`
|
|
255
|
-
| `updateGroup` | **Throws** `Call Userflow.init() before updateGroup()` | **Throws** `Call Userflow.identify() before updateGroup()`; also requires a prior `group()`
|
|
256
|
-
| `track` | **Throws** `Call Userflow.init() before track()` | **Throws** `Call Userflow.identify() before track()`. Network, rate-limit, and unexpected SDK errors are isolated (the promise resolves; see [isolation.md](docs/isolation.md)) |
|
|
257
|
-
| `updateScreen` | Silently buffers; included on the next channel join | Silently buffers
|
|
241
|
+
| Call | Before `init()` resolves | Before `identify()` |
|
|
242
|
+
| -------------------------------- | ------------------------------------------------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
243
|
+
| `identify` / `identifyAnonymous` | **Throws** `Call Userflow.init() before identify()` | — |
|
|
244
|
+
| `group` | **Throws** `Call Userflow.init() before group()` | **Throws** `Call Userflow.identify() before group()` |
|
|
245
|
+
| `updateUser` | **Throws** `Call Userflow.init() before updateUser()` | **Throws** `Call Userflow.identify() before updateUser()` |
|
|
246
|
+
| `updateGroup` | **Throws** `Call Userflow.init() before updateGroup()` | **Throws** `Call Userflow.identify() before updateGroup()`; also requires a prior `group()` |
|
|
247
|
+
| `track` | **Throws** `Call Userflow.init() before track()` | **Throws** `Call Userflow.identify() before track()`. Network, rate-limit, and unexpected SDK errors are isolated (the promise resolves; see [isolation.md](https://unpkg.com/@userflow-tech/react-native/docs/isolation.md)) |
|
|
248
|
+
| `updateScreen` | Silently buffers; included on the next channel join | Silently buffers |
|
|
258
249
|
|
|
259
250
|
Other rules:
|
|
260
251
|
|
|
@@ -271,7 +262,7 @@ Other rules:
|
|
|
271
262
|
Same-id re-identify merges attributes.
|
|
272
263
|
- Identity verification `signature` is optional in the type, but **required by
|
|
273
264
|
the server** when the environment has identity verification enabled. See
|
|
274
|
-
[docs/identity-verification.md](docs/identity-verification.md).
|
|
265
|
+
[docs/identity-verification.md](https://unpkg.com/@userflow-tech/react-native/docs/identity-verification.md).
|
|
275
266
|
|
|
276
267
|
## Localization
|
|
277
268
|
|
|
@@ -304,7 +295,7 @@ unmount or crash the host tree. `init` / `identify` still throw — a swallowed
|
|
|
304
295
|
identify would look like success. Native crashes and errors in **your** children
|
|
305
296
|
of `UserflowProvider` are out of scope.
|
|
306
297
|
|
|
307
|
-
Details: [docs/isolation.md](docs/isolation.md).
|
|
298
|
+
Details: [docs/isolation.md](https://unpkg.com/@userflow-tech/react-native/docs/isolation.md).
|
|
308
299
|
|
|
309
300
|
## Screen tracking
|
|
310
301
|
|
|
@@ -397,13 +388,13 @@ function InviteScreen() {
|
|
|
397
388
|
|
|
398
389
|
Targets inside a `ScrollView` / `FlatList` are scrolled into view automatically.
|
|
399
390
|
`useUserflowScrollContainer` is only needed as an override for scroll libraries
|
|
400
|
-
the fiber walk cannot drive — see [docs/anchoring.md](docs/anchoring.md).
|
|
391
|
+
the fiber walk cannot drive — see [docs/anchoring.md](https://unpkg.com/@userflow-tech/react-native/docs/anchoring.md).
|
|
401
392
|
|
|
402
393
|
In the Userflow builder, set the MANUAL step selector CSS to `#invite-teammates`
|
|
403
394
|
(or `invite-teammates`). Use `useUserflowAnchor(id)` only when you need an
|
|
404
395
|
explicit override (e.g. a third-party component that does not accept `testID`).
|
|
405
396
|
Full contract, prop priority, missing-target behavior, and duplicate-id rules:
|
|
406
|
-
[docs/anchoring.md](docs/anchoring.md).
|
|
397
|
+
[docs/anchoring.md](https://unpkg.com/@userflow-tech/react-native/docs/anchoring.md).
|
|
407
398
|
|
|
408
399
|
## Builder preview & pairing
|
|
409
400
|
|
|
@@ -448,8 +439,8 @@ Deep-link / pairing helpers:
|
|
|
448
439
|
| `PreviewModeBanner` | Mounted by `UserflowProvider` while paired. The top bar shows at once for a preview link, stays hidden for an element-selection link and after any pick until the next preview, and waits briefly on a link with no purpose. |
|
|
449
440
|
|
|
450
441
|
Full scheme registration, Linking ownership, and verify commands:
|
|
451
|
-
[docs/deep-linking.md](docs/deep-linking.md). Symptom table:
|
|
452
|
-
[docs/troubleshooting.md](docs/troubleshooting.md
|
|
442
|
+
[docs/deep-linking.md](https://unpkg.com/@userflow-tech/react-native/docs/deep-linking.md). Symptom table: the "Builder preview / pairing" section of
|
|
443
|
+
[docs/troubleshooting.md](https://unpkg.com/@userflow-tech/react-native/docs/troubleshooting.md).
|
|
453
444
|
|
|
454
445
|
## Connection resilience
|
|
455
446
|
|
|
@@ -480,33 +471,35 @@ Screen tracking ≠ action routing. React Navigation apps need
|
|
|
480
471
|
|
|
481
472
|
### `Userflow`
|
|
482
473
|
|
|
483
|
-
| Member
|
|
484
|
-
|
|
|
485
|
-
| `init(config)`
|
|
486
|
-
| `identify(userId, attributes?, options?)`
|
|
487
|
-
| `identifyAnonymous(attributes?, options?)`
|
|
488
|
-
| `group(groupId, attributes?, options?)`
|
|
489
|
-
| `updateUser(attributes?)`
|
|
490
|
-
| `updateGroup(attributes?, options?)`
|
|
491
|
-
| `track(name, attributes?, options?)`
|
|
492
|
-
| `reset()`
|
|
493
|
-
| `teardown()`
|
|
494
|
-
| `updateScreen(name)`
|
|
495
|
-
| `setOnNavigate(handler)`
|
|
496
|
-
| `reportActivity()`
|
|
497
|
-
| `didHandleURL(url)`
|
|
498
|
-
| `handlePairingUrl(url)`
|
|
499
|
-
| `exitPreview()`
|
|
500
|
-
| `
|
|
501
|
-
| `
|
|
502
|
-
| `
|
|
503
|
-
| `
|
|
504
|
-
| `
|
|
505
|
-
| `
|
|
506
|
-
| `
|
|
507
|
-
| `
|
|
508
|
-
| `
|
|
509
|
-
| `
|
|
474
|
+
| Member | Description |
|
|
475
|
+
| ------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
|
|
476
|
+
| `init(config)` | Validate credentials, store config, start lifecycle + network controllers. |
|
|
477
|
+
| `identify(userId, attributes?, options?)` | Identify a user; auto-sets `sdk` / `device_os` / `device_type` and `app_version` / `app_build` from init; `options.signature` for identity verification. |
|
|
478
|
+
| `identifyAnonymous(attributes?, options?)` | Stable anonymous id via AsyncStorage; auto-sets `sdk` / `device_os` / `device_type` and `app_version` / `app_build`. |
|
|
479
|
+
| `group(groupId, attributes?, options?)` | Associate the current user with a group. |
|
|
480
|
+
| `updateUser(attributes?)` | Upsert attributes for the current user without re-identifying. |
|
|
481
|
+
| `updateGroup(attributes?, options?)` | Upsert group / membership attributes without re-grouping. |
|
|
482
|
+
| `track(name, attributes?, options?)` | Record a custom event (literal attribute values only); `userOnly` skips group. Misuse (`UserflowAuthError`) rejects; network / rate-limit / SDK bugs are isolated. |
|
|
483
|
+
| `reset()` | Clear identity, the stored anonymous id, client conditions, and flow and banner sessions; disconnect. |
|
|
484
|
+
| `teardown()` | Stop AppState / NetInfo / screen-tracking subscriptions. |
|
|
485
|
+
| `updateScreen(name)` | Report the active screen (prefer hooks when possible). |
|
|
486
|
+
| `setOnNavigate(handler)` | Override or clear the host NAVIGATE handler. |
|
|
487
|
+
| `reportActivity()` | Reset the idle timer; reconnect an idle-suspended socket. |
|
|
488
|
+
| `didHandleURL(url)` | Handle a Userflow preview deep link (`…://?token=…`). |
|
|
489
|
+
| `handlePairingUrl(url)` | Handle a Builder pairing deep link (`…://?pairing_token=…`). Works in every build; the signed JWT gates the session. |
|
|
490
|
+
| `exitPreview()` | Leave Builder preview mode; disconnect the pairing websocket. Works in every build. |
|
|
491
|
+
| `setScrollPadding(padding)` | Sticky header/footer insets used when scrolling tooltip targets into view. |
|
|
492
|
+
| `setCustomScrollIntoView(fn)` | Replace scroll-into-view (e.g. unsupported scroll libraries). Pass `null` to restore the default. |
|
|
493
|
+
| `setSurfaceInteractionBlocking(enabled)` | `true` (default) blocks taps on the app under tooltip backdrops. `false` lets them through. Modals always block. |
|
|
494
|
+
| `setEvalJsContext(values)` | Values exposed to Evaluate JavaScript as `window.userflowContext.host`. Replaces the previous values. |
|
|
495
|
+
| `getUserId()` | Current user id, or `null` before identify. |
|
|
496
|
+
| `getAttributes()` | Copy of attributes for the current user. |
|
|
497
|
+
| `getFlowSessionEngine()` | Mid-flow session engine (created lazily; attach runs after identify). |
|
|
498
|
+
| `getBannerSessionEngine()` | Banner session engine (created lazily; attach runs after identify). |
|
|
499
|
+
| `getHostAppVersion()` | Host app native version cached at init, or `null` before init / when unavailable. |
|
|
500
|
+
| `getDeviceContext()` | Platform metadata cached during `init` (`sdk`, `deviceOs`, `deviceType`), or `null` before init. |
|
|
501
|
+
| `logHostAppVersion()` | Log the host app's native version (not `SDK_VERSION`) and platform OS. Uses bundled device-info on bare RN. |
|
|
502
|
+
| `logDeviceContext()` | Log cached user-attribute values (`sdk` / `device_os` / `device_type`). Requires `init`. |
|
|
510
503
|
|
|
511
504
|
### Hooks and components
|
|
512
505
|
|
|
@@ -519,8 +512,19 @@ Screen tracking ≠ action routing. React Navigation apps need
|
|
|
519
512
|
| `useUserflowScreen(name)` | Report the active screen from a React tree. |
|
|
520
513
|
| `useUserflowAnchor(id)` | Optional override: register a view as a MANUAL target (beats `userflowId` / `testID`). |
|
|
521
514
|
| `useUserflowScrollContainer(onScroll?)` | Optional override: register a `ScrollView` for tooltip scroll-into-view. |
|
|
522
|
-
| `
|
|
523
|
-
|
|
515
|
+
| `EmbedBannerPlaceholder` | Slot for a banner placed on an element (`<EmbedBannerPlaceholder id="welcome-banner" />` matches the selector `#welcome-banner`). Renders nothing until a matching banner is active. Top and bottom banners ignore it. |
|
|
516
|
+
|
|
517
|
+
### Pairing helpers
|
|
518
|
+
|
|
519
|
+
Named exports, not members of `Userflow`. Use them when your app owns `Linking`
|
|
520
|
+
and forwards URLs itself.
|
|
521
|
+
|
|
522
|
+
| Export | Description |
|
|
523
|
+
| ----------------------------- | ------------------------------------------------------------------------- |
|
|
524
|
+
| `inspectPairingDeepLink(url)` | Classify a URL as pairing without consuming it; reports rejection reason. |
|
|
525
|
+
| `isPairingAttempt(reason)` | True when a rejection was a recognisable pairing attempt worth reporting. |
|
|
526
|
+
| `parsePairingDeepLink(url)` | Parse a pairing deep link. |
|
|
527
|
+
| `isUserflowPairingUrl(url)` | Detect a pairing deep link. |
|
|
524
528
|
|
|
525
529
|
### Subpath exports
|
|
526
530
|
|
|
@@ -540,20 +544,22 @@ Screen tracking ≠ action routing. React Navigation apps need
|
|
|
540
544
|
|
|
541
545
|
## Guides in this package
|
|
542
546
|
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
|
547
|
-
|
|
|
548
|
-
| [docs/
|
|
549
|
-
| [docs/
|
|
550
|
-
| [docs/
|
|
547
|
+
These guides also ship in the package, under
|
|
548
|
+
`node_modules/@userflow-tech/react-native/docs/`.
|
|
549
|
+
|
|
550
|
+
| Doc | Topic |
|
|
551
|
+
| ------------------------------------------------------------------------------------------------------------ | ----------------------------------------------------------- |
|
|
552
|
+
| [docs/anchoring.md](https://unpkg.com/@userflow-tech/react-native/docs/anchoring.md) | Manual targets, scroll containers, missing-target behavior |
|
|
553
|
+
| [docs/isolation.md](https://unpkg.com/@userflow-tech/react-native/docs/isolation.md) | What “isolated as possible” means; overlay + `track` guards |
|
|
554
|
+
| [docs/deep-linking.md](https://unpkg.com/@userflow-tech/react-native/docs/deep-linking.md) | Builder preview URLs and pairing sessions |
|
|
555
|
+
| [docs/identity-verification.md](https://unpkg.com/@userflow-tech/react-native/docs/identity-verification.md) | HMAC signature on your backend |
|
|
556
|
+
| [docs/troubleshooting.md](https://unpkg.com/@userflow-tech/react-native/docs/troubleshooting.md) | Symptom → cause for common integration failures |
|
|
551
557
|
|
|
552
558
|
## Experimental
|
|
553
559
|
|
|
554
560
|
- AUTO / codeless element targeting (exact-id fast path + scored matcher;
|
|
555
561
|
scored path needs Babel full mode to populate the auto-anchor registry).
|
|
556
|
-
See [docs/anchoring.md](docs/anchoring.md).
|
|
562
|
+
See [docs/anchoring.md](https://unpkg.com/@userflow-tech/react-native/docs/anchoring.md).
|
|
557
563
|
- Build-time stamping with `@userflow-tech/react-native/babel-plugin`. Jest
|
|
558
564
|
runs the plugin too, which changes snapshots. Read
|
|
559
565
|
[Babel plugin and snapshot tests](#babel-plugin-and-snapshot-tests) before
|
|
@@ -709,4 +715,4 @@ the files it lists, not the components a test renders.
|
|
|
709
715
|
- `INPUT_VALUE` / `FILLED_IN_INPUT` client conditions
|
|
710
716
|
|
|
711
717
|
Flows gated on unsupported client conditions stay unknown and **never start**.
|
|
712
|
-
See [docs/troubleshooting.md](docs/troubleshooting.md).
|
|
718
|
+
See [docs/troubleshooting.md](https://unpkg.com/@userflow-tech/react-native/docs/troubleshooting.md).
|
package/docs/anchoring.md
CHANGED
|
@@ -16,7 +16,7 @@ Dashboard MANUAL selectors store a CSS-like string on `step.selector.css` (or
|
|
|
16
16
|
`condition.selector.css`). The SDK resolves it with:
|
|
17
17
|
|
|
18
18
|
```typescript
|
|
19
|
-
//
|
|
19
|
+
// src/anchors/resolveManualAnchorId.ts
|
|
20
20
|
return trimmed.startsWith('#') ? trimmed.slice(1) : trimmed;
|
|
21
21
|
```
|
|
22
22
|
|
|
@@ -318,7 +318,7 @@ Modals always block — the full-screen backdrop is a `Pressable` hit target.
|
|
|
318
318
|
Pass `Userflow.setSurfaceInteractionBlocking(false)` to restore the legacy
|
|
319
319
|
pass-through tooltip backdrop (`pointerEvents="none"` on dim bands) so the
|
|
320
320
|
host screen stays scrollable and tappable underneath. The `tooltipTargetBlocked`
|
|
321
|
-
hole seal is unchanged
|
|
321
|
+
hole seal is unchanged.
|
|
322
322
|
|
|
323
323
|
When a tooltip step has `backdrop: false`, the cutout still mounts with dim
|
|
324
324
|
opacity `0` so interaction blocking applies without a visible dim.
|
|
@@ -341,7 +341,7 @@ rect** via a pass-through bridge around app content (`TargetPressBridge` in
|
|
|
341
341
|
ELEMENT `CLICK` / `NOT_CLICK` auto-start conditions use the same bridge
|
|
342
342
|
(`elementTapMonitor`) and do not steal the press either. `MOUSEDOWN` and
|
|
343
343
|
`DISABLED` conditions are still unsupported — see
|
|
344
|
-
[
|
|
344
|
+
[troubleshooting.md](troubleshooting.md).
|
|
345
345
|
|
|
346
346
|
## Missing-target behavior
|
|
347
347
|
|
|
@@ -405,4 +405,3 @@ The Userflow overlay is a _sibling_ of the scan root, so SDK-owned `testID`s
|
|
|
405
405
|
|
|
406
406
|
- [troubleshooting.md](troubleshooting.md) — “flow never appeared” checklist
|
|
407
407
|
- [theme-mapping.md](theme-mapping.md) — chrome tokens that affect tooltip UI
|
|
408
|
-
- Repo `docs/client-conditions.md` (monorepo only) — track / toggle protocol internals
|
package/docs/troubleshooting.md
CHANGED
|
@@ -7,9 +7,6 @@ Messages are quoted exactly so you can search logs for them.
|
|
|
7
7
|
|
|
8
8
|
| Symptom / log message | Likely cause | Fix |
|
|
9
9
|
| ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
10
|
-
| `404` from `npm install` or `npm view @userflow-tech/react-native` | The npm token is missing, or the npm user or org is not on the read-only `@userflow-tech` team. npm returns 404 for a private package the caller cannot see. | Ask Userflow to add the npm user or org to the read-only team, then create a granular read-only token limited to `@userflow-tech`. |
|
|
11
|
-
| Yarn 2+ still 404s with a valid `.npmrc` | Yarn 2 and later ignore `.npmrc`. | Set `npmScopes.userflow-tech.npmRegistryServer` and `npmAuthToken` in `.yarnrc.yml`. |
|
|
12
|
-
| EAS or CI install 404s while local install works | `NPM_TOKEN` is not available to that environment. | Add `NPM_TOKEN` as an EAS secret or CI secret. The `.npmrc` line `//registry.npmjs.org/:_authToken=${NPM_TOKEN}` reads it at install time. |
|
|
13
10
|
| `expo doctor` reports `react-native-view-shot` | The app pins `^5.0.0` and Expo SDK 54's expected version is 4.0.3. | Keep the pin. Add `"react-native-view-shot"` to `expo.install.exclude`. |
|
|
14
11
|
| `Unable to resolve module` for an optional peer (`netinfo`, `expo-secure-store`, `expo-router`, safe-area, navigation) | A custom Metro config does not extend `getDefaultConfig`, so `allowOptionalDependencies` is off. | Extend `getDefaultConfig` from `expo/metro-config` or `@react-native/metro-config`. |
|
|
15
12
|
| `ERESOLVE` while installing `@userflow-tech/react-native` | The app already has a version outside a peer range: view-shot 4.0.3 (what unpinned `npx expo install` installs on Expo SDK 54), NetInfo 9.x, safe-area-context 3.x, WebView 13.6.x or 14.x, or React Native older than 0.76. | Move that package into the range in the package README. For view-shot, npm prints `Found: react-native-view-shot@4.0.3` and `peer react-native-view-shot@"^5.0.0" from @userflow-tech/react-native`. Install the SDK and `react-native-view-shot@^5.0.0` in one command, then add `"react-native-view-shot"` to `expo.install.exclude` on Expo SDK 54. Do not retry with `--force` or `--legacy-peer-deps`; that leaves 4.0.3 installed. Raise React Native to 0.76 or later when that is the conflict. |
|
|
@@ -135,7 +132,7 @@ Full setup: [deep-linking.md](deep-linking.md). Pairing is available in all buil
|
|
|
135
132
|
| Symptom | Fix |
|
|
136
133
|
| ----------------------------------------------------------------- | --------------------------------------------------------------------------------- |
|
|
137
134
|
| Crashes or missing native modules in Expo Go | Use a **development build**; Expo Go is not supported |
|
|
138
|
-
| Duplicate React / RN instance crashes when linking local packages |
|
|
135
|
+
| Duplicate React / RN instance crashes when linking local packages | Make Metro resolve `react` and `react-native` from the app's own `node_modules` |
|
|
139
136
|
| Preview / pairing scheme not registered | Add the `@userflow-tech/react-native` plugin with `schemeId`, then rebuild native |
|
|
140
137
|
|
|
141
138
|
## Jest
|
package/lib/commonjs/version.js
CHANGED
|
@@ -5,5 +5,5 @@ Object.defineProperty(exports, "__esModule", {
|
|
|
5
5
|
});
|
|
6
6
|
exports.SDK_VERSION = void 0;
|
|
7
7
|
/** Generated by scripts/write-version.mjs — do not edit. */
|
|
8
|
-
const SDK_VERSION = exports.SDK_VERSION = '0.4.
|
|
8
|
+
const SDK_VERSION = exports.SDK_VERSION = '0.4.1';
|
|
9
9
|
//# sourceMappingURL=version.js.map
|
package/lib/module/version.js
CHANGED
package/package.json
CHANGED
package/src/version.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
/** Generated by scripts/write-version.mjs — do not edit. */
|
|
2
|
-
export const SDK_VERSION = '0.4.
|
|
2
|
+
export const SDK_VERSION = '0.4.1';
|
package/vendor/core/package.json
CHANGED
package/docs/theme-mapping.md
DELETED
|
@@ -1,130 +0,0 @@
|
|
|
1
|
-
# Theme mapping (web → React Native)
|
|
2
|
-
|
|
3
|
-
Phase 3 maps Userflow web theme tokens onto React Native styles used by flow chrome.
|
|
4
|
-
This is an interim visual baseline aligned with the mobile tooltip/modal design specs.
|
|
5
|
-
|
|
6
|
-
## Card chrome — `resolveBubbleChrome`
|
|
7
|
-
|
|
8
|
-
Source: `src/surfaces/themeChrome.ts`
|
|
9
|
-
|
|
10
|
-
| Web / theme token | RN usage |
|
|
11
|
-
| ----------------------------------------- | ---------------------------------------------------------------- |
|
|
12
|
-
| `backgroundColor` | Card `backgroundColor` |
|
|
13
|
-
| `bubbleBorderRadius` (default `10`) | Card `borderRadius` |
|
|
14
|
-
| `bubbleBorderWidth` / `bubbleBorderColor` | Card border |
|
|
15
|
-
| `tooltipNotchSize` (default `10`) | Tooltip notch size; `0` hides notch |
|
|
16
|
-
| Modal content padding | `24` (mobile; web default is 40) |
|
|
17
|
-
| Tooltip / bubble content padding | `24` (web tooltip) |
|
|
18
|
-
| Shadow | Approximate dual drop-shadow via `shadow*` + Android `elevation` |
|
|
19
|
-
|
|
20
|
-
Modal cards use `overflow: 'hidden'` so the progress bar clips to the radius.
|
|
21
|
-
Tooltip cards use `overflow: 'visible'` so the notch is not clipped.
|
|
22
|
-
|
|
23
|
-
## Progress — `ProgressBar`
|
|
24
|
-
|
|
25
|
-
| Theme token | RN usage |
|
|
26
|
-
| ---------------------------------------- | ------------------------------------------------- |
|
|
27
|
-
| `progressBarEnabled` | Show / hide |
|
|
28
|
-
| `progressBarPosition` (`TOP` / `BOTTOM`) | Placement flush on the card edge |
|
|
29
|
-
| `progressBarType` | `DEFAULT` fraction bar; `NUMBERED` shows `1 of N` |
|
|
30
|
-
| Step `progress` + step index | Fraction via `resolveStepProgress` |
|
|
31
|
-
|
|
32
|
-
## Buttons — `StepButton`
|
|
33
|
-
|
|
34
|
-
| Theme token | RN usage |
|
|
35
|
-
| ------------------------------- | ---------------------------------------------------------------- |
|
|
36
|
-
| `primaryButton*` / widget brand | Primary filled button |
|
|
37
|
-
| Secondary (DEFAULT) | Neutral outline: white fill, `#d1d5db` border, `fontColor` label |
|
|
38
|
-
| Button fragment colors when set | Override defaults per button |
|
|
39
|
-
|
|
40
|
-
## Backdrop & cutout
|
|
41
|
-
|
|
42
|
-
| Theme token | RN usage |
|
|
43
|
-
| ------------------------------------------------------------ | -------------------------------------------------------------------------------------------------------------------- |
|
|
44
|
-
| `backdropColor` | Modal full-screen backdrop; tooltip cutout fill |
|
|
45
|
-
| `backdropOpacity` | Parsed float (`parseBackdropOpacity`) |
|
|
46
|
-
| `modalBackdropOnclick` | `DISMISS` → tap backdrop ends flow |
|
|
47
|
-
| Step `backdrop` / `backdropPadding` / `tooltipTargetBlocked` | Tooltip cutout hole, dim, and interaction blocking (bands block by default; hole sealed when `tooltipTargetBlocked`) |
|
|
48
|
-
|
|
49
|
-
## Tooltip target highlight
|
|
50
|
-
|
|
51
|
-
Source: `src/surfaces/resolveHighlightChrome.ts` + `src/surfaces/tooltip/TooltipHighlight.tsx`.
|
|
52
|
-
|
|
53
|
-
Web paints the ring as one CSS `box-shadow` on `.userflowjs-tooltip-backdrop`.
|
|
54
|
-
RN uses a **2px brand stroke + one translucent halo**, plus iOS `shadow*` /
|
|
55
|
-
Android `boxShadow` for blur. Theme spread is a placement gap only — it is
|
|
56
|
-
not painted as a thick solid bar.
|
|
57
|
-
|
|
58
|
-
| Web / theme token | RN usage |
|
|
59
|
-
| -------------------------- | -------------------------------------------------------------------------------- |
|
|
60
|
-
| `backdropHighlightColor` | Stroke color. Near-white (web default `#ffffff`) is treated as unset — see below |
|
|
61
|
-
| `backdropHighlightOpacity` | Caps the halo at `0.32` so it stays a wash |
|
|
62
|
-
| `backdropHighlightRadius` | Halo thickness (default `4`) |
|
|
63
|
-
| `backdropHighlightSpread` | Added to placement pad when type is `OUTSIDE` (default `0`). Not stroke width |
|
|
64
|
-
| `backdropHighlightType` | `OUTSIDE` (default) draws outside the hole; `INSIDE` insets |
|
|
65
|
-
|
|
66
|
-
Placement pad for `OUTSIDE` is `spread + strokeWidth + radius` so the tooltip
|
|
67
|
-
sits clear of the painted ring, not only the theme spread token.
|
|
68
|
-
| Corner radius | `8` + `backdropPadding` (web copies the target's computed radius; RN measure cannot) |
|
|
69
|
-
|
|
70
|
-
Color fallback: non-white `backdropHighlightColor` → `widgetBackgroundColor` →
|
|
71
|
-
`brandBackgroundColor` → `defaultButtonBackgroundColor` → `#1a57e6`. Web's
|
|
72
|
-
`#ffffff` default is skipped so the dimmed cutout does not get a white frame.
|
|
73
|
-
|
|
74
|
-
## Typography
|
|
75
|
-
|
|
76
|
-
| Theme token | RN usage |
|
|
77
|
-
| ------------ | ----------------------------------- |
|
|
78
|
-
| `fontColor` | Body / heading / close affordance |
|
|
79
|
-
| `fontSize` | Base body size |
|
|
80
|
-
| `fontFamily` | Applied where Text styles accept it |
|
|
81
|
-
|
|
82
|
-
## Quote / code-block — TreeDoc chrome
|
|
83
|
-
|
|
84
|
-
Source of truth: web `userflowjs/styles/bubble-frame.styl` in the main Userflow
|
|
85
|
-
web repo (blockquote / `code` / `pre > code`) and TreeDoc markup
|
|
86
|
-
(`blockquote`, `pre > code`). Spacing tokens from web `$padding-*` assume
|
|
87
|
-
**1rem = 16px**.
|
|
88
|
-
|
|
89
|
-
Implementation: `src/content/RichContentRenderer.tsx` + `src/content/themeColor.ts`.
|
|
90
|
-
|
|
91
|
-
| Token | rem | RN px |
|
|
92
|
-
| ------------- | ----- | ----- |
|
|
93
|
-
| `$padding-2` | 0.125 | 2 |
|
|
94
|
-
| `$padding-4` | 0.25 | 4 |
|
|
95
|
-
| `$padding-8` | 0.5 | 8 |
|
|
96
|
-
| `$padding-16` | 1 | 16 |
|
|
97
|
-
|
|
98
|
-
Root content uses `gap: 8` (`ROOT_CONTENT_GAP`). Quote/code add
|
|
99
|
-
`marginBottom: 8` when not last so gap + margin ≈ web’s 16px block spacing.
|
|
100
|
-
|
|
101
|
-
### Quote (`blockquote`)
|
|
102
|
-
|
|
103
|
-
| Web rule | RN |
|
|
104
|
-
| ----------------------------------------------- | -------------------------------------------------------------------------------- |
|
|
105
|
-
| `border-inline-start: 2px solid rgba(fg, 0.15)` | `borderStartWidth: 2`, `borderStartColor` via `foregroundAlpha(fontColor, 0.15)` |
|
|
106
|
-
| `padding: $padding-4 $padding-16` | `paddingVertical: 4`, `paddingHorizontal: 16` |
|
|
107
|
-
| `margin-bottom: $padding-16` when not last | `marginBottom: 8` (+ root gap 8); last painted sibling: 0 |
|
|
108
|
-
| `min-height: var(--userflow-line-height, 24px)` | `minHeight: 24` |
|
|
109
|
-
| Not italic by default | No forced `fontStyle: 'italic'` |
|
|
110
|
-
|
|
111
|
-
### Code-block (`pre > code`) and inline `code` mark
|
|
112
|
-
|
|
113
|
-
| Web rule | RN |
|
|
114
|
-
| -------------------------------------------------------------------------- | ------------------------------------------------------------------ |
|
|
115
|
-
| Mono stack (`SFMono-Regular, Consolas, Liberation Mono, Menlo, monospace`) | iOS `Menlo`, Android `monospace` |
|
|
116
|
-
| `font-size: calc(font-size * 0.875)` | `fontSize * 0.875` |
|
|
117
|
-
| `background: rgba(fg, 0.05)` | `foregroundAlpha(fontColor, 0.05)` (hex / rgb / rgba) |
|
|
118
|
-
| `border-radius: calc(font-size * 0.25)` | `fontSize * 0.25` |
|
|
119
|
-
| `pre > code` padding `$padding-8` | `padding: 8` + horizontal `ScrollView` (`nestedScrollEnabled`) |
|
|
120
|
-
| Inline `code` padding `$padding-2 $padding-4` | View chrome wrapper + `paddingVertical: 2`, `paddingHorizontal: 4` |
|
|
121
|
-
|
|
122
|
-
## Safe area
|
|
123
|
-
|
|
124
|
-
Surfaces pad with `useSurfaceLayoutInsets`: optional-peer
|
|
125
|
-
`react-native-safe-area-context` (zero fallback) plus a 24px screen margin so
|
|
126
|
-
cards clear Dynamic Island / home indicator regions. While Builder preview is
|
|
127
|
-
active, the measured Preview banner height is added to the top inset so the
|
|
128
|
-
close control is not trapped under the banner. Tall cards cap at that padded
|
|
129
|
-
window height and scroll internally (`overflow: 'hidden'` on the fill; the
|
|
130
|
-
shadow/notch shell stays `overflow: 'visible'`).
|