@getuserfeedback/react-native 2.0.24 → 3.0.2
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
CHANGED
|
@@ -52,6 +52,8 @@ export function App() {
|
|
|
52
52
|
|
|
53
53
|
`GetUserFeedbackProvider` renders `WidgetHost` internally, auto-enqueues `init`, measures the React Native window for the hosted WebView viewport, shows the hosted WebView inside a native bottom sheet while a flow is loading or open, and resolves command promises when the WebView transport reports command settlement. Pass either `loaderUrl` or a custom WebView `source` so the hosted WebView has a loader runtime to execute commands. Use `onCommandError` to receive automatic setup failures from `init` or `configure`.
|
|
54
54
|
|
|
55
|
+
Custom `source` documents must implement the current WebView transport contract. Provider-owned presentation is driven by `instance:view-host:snapshots-changed`; the legacy aggregate `instance:flow:state-changed:instance` event does not control the native sheet.
|
|
56
|
+
|
|
55
57
|
`WidgetHost` remains exported for advanced hosts that need direct WebView control.
|
|
56
58
|
|
|
57
59
|
The host message types are re-exported from `@getuserfeedback/protocol/webview-transport` through package-owned aliases so the React Native package stays aligned with the shared WebView transport contract.
|
package/dist/index.js
CHANGED
|
@@ -15,7 +15,7 @@ import { createContext, createElement, useCallback, useContext, useEffect, useMe
|
|
|
15
15
|
import { useResolvedHostViewport } from "./host-viewport.js";
|
|
16
16
|
import { toCommandSettlementError, toReactNativeOneShotCommand, } from "./provider-command-helpers.js";
|
|
17
17
|
import { useProviderCommandTransport } from "./provider-command-transport.js";
|
|
18
|
-
import { createProviderWidgetHostLifecycleController, HIDDEN_PROVIDER_WIDGET_HOST_VISIBILITY,
|
|
18
|
+
import { createProviderWidgetHostLifecycleController, HIDDEN_PROVIDER_WIDGET_HOST_VISIBILITY, } from "./provider-widget-host-lifecycle.js";
|
|
19
19
|
import { ProviderWidgetHostOverlay, toProviderWidgetHostStyle, toProviderWidgetSheetHostLayoutPlan, } from "./provider-widget-host-overlay.js";
|
|
20
20
|
import { REACT_NATIVE_SDK_VERSION } from "./version.js";
|
|
21
21
|
import { WidgetHost, } from "./widget-host.js";
|
|
@@ -226,7 +226,7 @@ export function GetUserFeedbackProvider({ autoInit = true, children, commandTime
|
|
|
226
226
|
const flowRunsRef = useRef(new Map());
|
|
227
227
|
const flowRunControllerOptionsRef = useRef(null);
|
|
228
228
|
const widgetHostLifecycle = widgetHostLifecycleRef.current;
|
|
229
|
-
const { clearFlowHandleFromVisibility, getCurrentHostEpoch, isWidgetHostVisible: resolveIsWidgetHostVisible, markNotReady, markReady, replaceViewHostSnapshots, syncHostSourceKey,
|
|
229
|
+
const { clearFlowHandleFromVisibility, getCurrentHostEpoch, isWidgetHostVisible: resolveIsWidgetHostVisible, markNotReady, markReady, replaceViewHostSnapshots, syncHostSourceKey, toReadyVisibility, } = widgetHostLifecycle;
|
|
230
230
|
const createCommandTimeoutError = useCallback((requestId) => new CommandSettlementTimeoutError(requestId), []);
|
|
231
231
|
const transport = useProviderCommandTransport({
|
|
232
232
|
commandTimeoutMs,
|
|
@@ -437,7 +437,9 @@ export function GetUserFeedbackProvider({ autoInit = true, children, commandTime
|
|
|
437
437
|
clearIdleFlowHandles();
|
|
438
438
|
didReissueDeliveredCommands = reissueDeliveredPendingActionCommands();
|
|
439
439
|
}
|
|
440
|
-
setWidgetHostVisibility((visibility) =>
|
|
440
|
+
setWidgetHostVisibility((visibility) => readyResult.didResetHostEpoch
|
|
441
|
+
? HIDDEN_PROVIDER_WIDGET_HOST_VISIBILITY
|
|
442
|
+
: toReadyVisibility(visibility, event));
|
|
441
443
|
enqueueStartupCommands({ force: readyResult.previousReady !== null });
|
|
442
444
|
startPendingCommandTimeouts();
|
|
443
445
|
return didReissueDeliveredCommands;
|
|
@@ -485,17 +487,6 @@ export function GetUserFeedbackProvider({ autoInit = true, children, commandTime
|
|
|
485
487
|
}
|
|
486
488
|
setWidgetHostVisibility((visibility) => clearFlowHandleFromVisibility(visibility, flowHandleId));
|
|
487
489
|
}, [clearFlowHandleFromVisibility]);
|
|
488
|
-
const handleInstanceFlowStateChanged = useCallback((detail) => {
|
|
489
|
-
const snapshot = toProviderWidgetHostSnapshot(detail, instanceId);
|
|
490
|
-
if (!snapshot) {
|
|
491
|
-
return;
|
|
492
|
-
}
|
|
493
|
-
const visibility = toHostSnapshotVisibility(snapshot);
|
|
494
|
-
if (!visibility) {
|
|
495
|
-
return;
|
|
496
|
-
}
|
|
497
|
-
setWidgetHostVisibility(visibility);
|
|
498
|
-
}, [instanceId, toHostSnapshotVisibility]);
|
|
499
490
|
const handleWebMessage = useCallback((message) => {
|
|
500
491
|
if (message.kind === "hostEvent" &&
|
|
501
492
|
message.event.name === "instance:handle:invalidated" &&
|
|
@@ -504,11 +495,10 @@ export function GetUserFeedbackProvider({ autoInit = true, children, commandTime
|
|
|
504
495
|
}
|
|
505
496
|
if (message.kind === "hostEvent" &&
|
|
506
497
|
message.event.name === "instance:view-host:snapshots-changed") {
|
|
507
|
-
replaceViewHostSnapshots(message.event.detail, instanceId);
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
handleInstanceFlowStateChanged(message.event.detail);
|
|
498
|
+
const visibility = replaceViewHostSnapshots(message.event.detail, instanceId);
|
|
499
|
+
if (visibility) {
|
|
500
|
+
setWidgetHostVisibility(visibility);
|
|
501
|
+
}
|
|
512
502
|
}
|
|
513
503
|
if (message.kind === "hostEvent" &&
|
|
514
504
|
message.event.name === "instance:command:settled") {
|
|
@@ -550,7 +540,6 @@ export function GetUserFeedbackProvider({ autoInit = true, children, commandTime
|
|
|
550
540
|
getCurrentHostEpoch,
|
|
551
541
|
getPendingCommand,
|
|
552
542
|
handleFlowHandleInvalidated,
|
|
553
|
-
handleInstanceFlowStateChanged,
|
|
554
543
|
instanceId,
|
|
555
544
|
onWebMessage,
|
|
556
545
|
replaceViewHostSnapshots,
|
|
@@ -14,25 +14,6 @@ export type ProviderWidgetHostVisibility = {
|
|
|
14
14
|
transitionPolicy?: WidgetLayoutTransitionPolicy;
|
|
15
15
|
transitionPolicySequence?: number;
|
|
16
16
|
};
|
|
17
|
-
type ProviderWidgetHostFlowState = {
|
|
18
|
-
height?: number;
|
|
19
|
-
flowHandleId?: string;
|
|
20
|
-
instanceId: string;
|
|
21
|
-
isLoading: boolean;
|
|
22
|
-
isOpen: boolean;
|
|
23
|
-
shouldRender?: boolean;
|
|
24
|
-
transitionPolicy?: WidgetLayoutTransitionPolicy;
|
|
25
|
-
width?: number;
|
|
26
|
-
};
|
|
27
|
-
type ProviderWidgetHostSnapshot = {
|
|
28
|
-
flowHandleId?: string;
|
|
29
|
-
height?: number;
|
|
30
|
-
isLoading: boolean;
|
|
31
|
-
isOpen: boolean;
|
|
32
|
-
shouldRender: boolean;
|
|
33
|
-
transitionPolicy?: WidgetLayoutTransitionPolicy;
|
|
34
|
-
width?: number;
|
|
35
|
-
};
|
|
36
17
|
export declare const HIDDEN_PROVIDER_WIDGET_HOST_VISIBILITY: ProviderWidgetHostVisibility;
|
|
37
18
|
export type ProviderWidgetHostLifecycleController = {
|
|
38
19
|
clearFlowHandleFromVisibility: (visibility: ProviderWidgetHostVisibility, flowHandleId: string) => ProviderWidgetHostVisibility;
|
|
@@ -52,14 +33,12 @@ export type ProviderWidgetHostLifecycleController = {
|
|
|
52
33
|
didResetHostEpoch: boolean;
|
|
53
34
|
previousReady: ProviderWidgetHostReadyState | null;
|
|
54
35
|
};
|
|
55
|
-
replaceViewHostSnapshots: (detail: InstanceViewHostSnapshotsChangedDetail, instanceId: string) =>
|
|
36
|
+
replaceViewHostSnapshots: (detail: InstanceViewHostSnapshotsChangedDetail, instanceId: string) => ProviderWidgetHostVisibility | null;
|
|
56
37
|
syncHostSourceKey: (hostSourceKey: string) => boolean;
|
|
57
|
-
toHostSnapshotVisibility: (snapshot: ProviderWidgetHostSnapshot) => ProviderWidgetHostVisibility | null;
|
|
58
38
|
toReadyVisibility: (visibility: ProviderWidgetHostVisibility, event: {
|
|
59
39
|
readySequence: number;
|
|
60
40
|
sourceKey: string;
|
|
61
41
|
}) => ProviderWidgetHostVisibility;
|
|
62
42
|
};
|
|
63
|
-
export declare function toProviderWidgetHostSnapshot(detail: ProviderWidgetHostFlowState, instanceId: string): ProviderWidgetHostSnapshot | null;
|
|
64
43
|
export declare function createProviderWidgetHostLifecycleController(initialHostSourceKey: string): ProviderWidgetHostLifecycleController;
|
|
65
44
|
export {};
|
|
@@ -1,25 +1,10 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { areViewHostSnapshotsEqual, cloneViewHostSnapshots, } from "@getuserfeedback/protocol/host";
|
|
2
2
|
export const HIDDEN_PROVIDER_WIDGET_HOST_VISIBILITY = {
|
|
3
3
|
hostSourceVersion: null,
|
|
4
4
|
isVisible: false,
|
|
5
5
|
readySequence: null,
|
|
6
6
|
sourceKey: null,
|
|
7
7
|
};
|
|
8
|
-
export function toProviderWidgetHostSnapshot(detail, instanceId) {
|
|
9
|
-
if (detail.instanceId !== instanceId) {
|
|
10
|
-
return null;
|
|
11
|
-
}
|
|
12
|
-
const snapshot = {
|
|
13
|
-
flowHandleId: detail.flowHandleId,
|
|
14
|
-
height: detail.height,
|
|
15
|
-
isLoading: detail.isLoading,
|
|
16
|
-
isOpen: detail.isOpen,
|
|
17
|
-
shouldRender: resolveInstanceFlowStateShouldRender(detail),
|
|
18
|
-
transitionPolicy: detail.transitionPolicy,
|
|
19
|
-
width: detail.width,
|
|
20
|
-
};
|
|
21
|
-
return snapshot;
|
|
22
|
-
}
|
|
23
8
|
export function createProviderWidgetHostLifecycleController(initialHostSourceKey) {
|
|
24
9
|
let hostEpoch = 0;
|
|
25
10
|
let hostSourceKey = initialHostSourceKey;
|
|
@@ -27,6 +12,27 @@ export function createProviderWidgetHostLifecycleController(initialHostSourceKey
|
|
|
27
12
|
let lastReady = null;
|
|
28
13
|
let transitionPolicySequence = 0;
|
|
29
14
|
let viewHostSnapshots = [];
|
|
15
|
+
let selectedViewHostSnapshot;
|
|
16
|
+
const toVisibility = (snapshot) => {
|
|
17
|
+
if (lastReady === null) {
|
|
18
|
+
return null;
|
|
19
|
+
}
|
|
20
|
+
let nextTransitionPolicySequence;
|
|
21
|
+
if (snapshot.transitionPolicy !== undefined) {
|
|
22
|
+
transitionPolicySequence += 1;
|
|
23
|
+
nextTransitionPolicySequence = transitionPolicySequence;
|
|
24
|
+
}
|
|
25
|
+
return {
|
|
26
|
+
flowHeight: snapshot.height,
|
|
27
|
+
flowHandleId: snapshot.flowHandleId,
|
|
28
|
+
hostSourceVersion,
|
|
29
|
+
isVisible: snapshot.shouldRender,
|
|
30
|
+
readySequence: lastReady.readySequence,
|
|
31
|
+
sourceKey: lastReady.sourceKey,
|
|
32
|
+
transitionPolicy: snapshot.transitionPolicy,
|
|
33
|
+
transitionPolicySequence: nextTransitionPolicySequence,
|
|
34
|
+
};
|
|
35
|
+
};
|
|
30
36
|
return {
|
|
31
37
|
clearFlowHandleFromVisibility: (visibility, flowHandleId) => visibility.flowHandleId === flowHandleId
|
|
32
38
|
? Object.assign(Object.assign({}, visibility), { flowHandleId: undefined }) : visibility,
|
|
@@ -44,6 +50,7 @@ export function createProviderWidgetHostLifecycleController(initialHostSourceKey
|
|
|
44
50
|
}
|
|
45
51
|
lastReady = null;
|
|
46
52
|
viewHostSnapshots = [];
|
|
53
|
+
selectedViewHostSnapshot = undefined;
|
|
47
54
|
return { wasReady };
|
|
48
55
|
},
|
|
49
56
|
markReady: (event, { hasDeliveredPendingCommands }) => {
|
|
@@ -61,6 +68,7 @@ export function createProviderWidgetHostLifecycleController(initialHostSourceKey
|
|
|
61
68
|
if (didResetHostEpoch) {
|
|
62
69
|
hostEpoch += 1;
|
|
63
70
|
viewHostSnapshots = [];
|
|
71
|
+
selectedViewHostSnapshot = undefined;
|
|
64
72
|
}
|
|
65
73
|
lastReady = Object.assign(Object.assign({}, event), { hostEpoch });
|
|
66
74
|
return {
|
|
@@ -71,10 +79,22 @@ export function createProviderWidgetHostLifecycleController(initialHostSourceKey
|
|
|
71
79
|
},
|
|
72
80
|
replaceViewHostSnapshots: (detail, instanceId) => {
|
|
73
81
|
if (detail.instanceId !== instanceId || lastReady === null) {
|
|
74
|
-
return
|
|
82
|
+
return null;
|
|
75
83
|
}
|
|
76
84
|
viewHostSnapshots = cloneViewHostSnapshots(detail.snapshots);
|
|
77
|
-
|
|
85
|
+
const nextSelectedSnapshot = viewHostSnapshots[0];
|
|
86
|
+
if (areViewHostSnapshotsEqual(selectedViewHostSnapshot, nextSelectedSnapshot)) {
|
|
87
|
+
return null;
|
|
88
|
+
}
|
|
89
|
+
selectedViewHostSnapshot = nextSelectedSnapshot;
|
|
90
|
+
if (!nextSelectedSnapshot) {
|
|
91
|
+
return toVisibility({
|
|
92
|
+
isLoading: false,
|
|
93
|
+
isOpen: false,
|
|
94
|
+
shouldRender: false,
|
|
95
|
+
});
|
|
96
|
+
}
|
|
97
|
+
return toVisibility(Object.assign(Object.assign({}, nextSelectedSnapshot), { shouldRender: true }));
|
|
78
98
|
},
|
|
79
99
|
syncHostSourceKey: (nextHostSourceKey) => {
|
|
80
100
|
if (hostSourceKey === nextHostSourceKey) {
|
|
@@ -84,28 +104,9 @@ export function createProviderWidgetHostLifecycleController(initialHostSourceKey
|
|
|
84
104
|
hostSourceVersion += 1;
|
|
85
105
|
lastReady = null;
|
|
86
106
|
viewHostSnapshots = [];
|
|
107
|
+
selectedViewHostSnapshot = undefined;
|
|
87
108
|
return true;
|
|
88
109
|
},
|
|
89
|
-
toHostSnapshotVisibility: (snapshot) => {
|
|
90
|
-
if (lastReady === null) {
|
|
91
|
-
return null;
|
|
92
|
-
}
|
|
93
|
-
let nextTransitionPolicySequence;
|
|
94
|
-
if (snapshot.transitionPolicy !== undefined) {
|
|
95
|
-
transitionPolicySequence += 1;
|
|
96
|
-
nextTransitionPolicySequence = transitionPolicySequence;
|
|
97
|
-
}
|
|
98
|
-
return {
|
|
99
|
-
flowHeight: snapshot.height,
|
|
100
|
-
flowHandleId: snapshot.flowHandleId,
|
|
101
|
-
hostSourceVersion,
|
|
102
|
-
isVisible: snapshot.shouldRender,
|
|
103
|
-
readySequence: lastReady.readySequence,
|
|
104
|
-
sourceKey: lastReady.sourceKey,
|
|
105
|
-
transitionPolicy: snapshot.transitionPolicy,
|
|
106
|
-
transitionPolicySequence: nextTransitionPolicySequence,
|
|
107
|
-
};
|
|
108
|
-
},
|
|
109
110
|
toReadyVisibility: (visibility, event) => {
|
|
110
111
|
if (!visibility.isVisible ||
|
|
111
112
|
visibility.sourceKey !== event.sourceKey ||
|
package/dist/version.js
CHANGED
|
@@ -3,4 +3,4 @@ const reactNativeSdkVersion = typeof __GX_REACT_NATIVE_SDK_VERSION__ === "string
|
|
|
3
3
|
: "";
|
|
4
4
|
// Build scripts patch this fallback to the package version for published artifacts.
|
|
5
5
|
// Source-linked workspace usage keeps the local fallback.
|
|
6
|
-
export const REACT_NATIVE_SDK_VERSION = reactNativeSdkVersion.length > 0 ? reactNativeSdkVersion : "
|
|
6
|
+
export const REACT_NATIVE_SDK_VERSION = reactNativeSdkVersion.length > 0 ? reactNativeSdkVersion : "3.0.2";
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
// ../view-orchestration/src/view-activation-machine.ts
|
|
2
|
+
import { createMachine, interpret, state, transition } from "robot3";
|
|
3
|
+
var VIEW_ACTIVATION_STATES = {
|
|
4
|
+
idle: true,
|
|
5
|
+
prerendering: true,
|
|
6
|
+
"activation-requested": true,
|
|
7
|
+
"prerendering-activation-requested": true,
|
|
8
|
+
prerendered: true,
|
|
9
|
+
active: true
|
|
10
|
+
};
|
|
11
|
+
function createViewActivationMachine() {
|
|
12
|
+
const states = {
|
|
13
|
+
idle: state(transition("startPrerender", "prerendering"), transition("requestActivation", "activation-requested")),
|
|
14
|
+
prerendering: state(transition("requestActivation", "prerendering-activation-requested"), transition("markPrerendered", "prerendered")),
|
|
15
|
+
"activation-requested": state(transition("startPrerender", "prerendering-activation-requested")),
|
|
16
|
+
"prerendering-activation-requested": state(transition("markPrerendered", "active")),
|
|
17
|
+
prerendered: state(transition("requestActivation", "active")),
|
|
18
|
+
active: state()
|
|
19
|
+
};
|
|
20
|
+
return createMachine(states, () => ({}));
|
|
21
|
+
}
|
|
22
|
+
function createViewActivationController() {
|
|
23
|
+
const machine = createViewActivationMachine();
|
|
24
|
+
const service = interpret(machine, () => {});
|
|
25
|
+
const getState = () => readViewActivationState(service.machine.current);
|
|
26
|
+
const send = (event) => {
|
|
27
|
+
service.send(event);
|
|
28
|
+
};
|
|
29
|
+
return {
|
|
30
|
+
getState,
|
|
31
|
+
startPrerender: () => {
|
|
32
|
+
send({ type: "startPrerender" });
|
|
33
|
+
},
|
|
34
|
+
requestActivation: () => {
|
|
35
|
+
send({ type: "requestActivation" });
|
|
36
|
+
},
|
|
37
|
+
markPrerendered: () => {
|
|
38
|
+
send({ type: "markPrerendered" });
|
|
39
|
+
}
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
function readViewActivationState(value) {
|
|
43
|
+
if (typeof value !== "string" || !(value in VIEW_ACTIVATION_STATES)) {
|
|
44
|
+
throw new Error(`Unknown view activation state: ${String(value)}`);
|
|
45
|
+
}
|
|
46
|
+
return value;
|
|
47
|
+
}
|
|
48
|
+
// src/view-orchestration-runtime.ts
|
|
49
|
+
function createViewActivationController2() {
|
|
50
|
+
return createViewActivationController();
|
|
51
|
+
}
|
|
52
|
+
export {
|
|
53
|
+
createViewActivationController2 as createViewActivationController
|
|
54
|
+
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@getuserfeedback/react-native",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "3.0.2",
|
|
4
4
|
"description": "getuserfeedback React Native SDK",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"getuserfeedback",
|
|
@@ -34,18 +34,18 @@
|
|
|
34
34
|
"scripts": {
|
|
35
35
|
"prepack": "node scripts/prepack.cjs",
|
|
36
36
|
"postpack": "node scripts/postpack.cjs",
|
|
37
|
-
"pack:verify": "
|
|
38
|
-
"publish:dry-run": "node ../../scripts/publish-package.cjs . --expect-dependency @getuserfeedback/protocol:../protocol/package.json --expect-dependency @getuserfeedback/sdk:../sdk/package.json -- --dry-run",
|
|
39
|
-
"publish:npm": "node ../../scripts/publish-package.cjs . --expect-dependency @getuserfeedback/protocol:../protocol/package.json --expect-dependency @getuserfeedback/sdk:../sdk/package.json",
|
|
37
|
+
"pack:verify": "bun scripts/verify-packed-runtime.ts",
|
|
38
|
+
"publish:dry-run": "node ../../scripts/publish-package.cjs . --verify-packed-runtime scripts/verify-packed-runtime.ts --expect-dependency @getuserfeedback/protocol:../protocol/package.json --expect-dependency @getuserfeedback/sdk:../sdk/package.json -- --dry-run",
|
|
39
|
+
"publish:npm": "node ../../scripts/publish-package.cjs . --verify-packed-runtime scripts/verify-packed-runtime.ts --expect-dependency @getuserfeedback/protocol:../protocol/package.json --expect-dependency @getuserfeedback/sdk:../sdk/package.json",
|
|
40
40
|
"build": "bun scripts/build.ts",
|
|
41
|
-
"typecheck": "tsc -
|
|
41
|
+
"typecheck": "tsc -p tsconfig.json --noEmit --tsBuildInfoFile tsconfig.typecheck.tsbuildinfo && tsc -p tsconfig-scripts.json",
|
|
42
42
|
"test": "bun test --dots",
|
|
43
43
|
"test:changed": "bun test --changed=${TEST_CHANGED_BASE:-HEAD} --pass-with-no-tests --dots",
|
|
44
44
|
"lint": "biome check ."
|
|
45
45
|
},
|
|
46
46
|
"dependencies": {
|
|
47
|
-
"@getuserfeedback/protocol": "^3.
|
|
48
|
-
"@getuserfeedback/sdk": "^0.8.
|
|
47
|
+
"@getuserfeedback/protocol": "^3.4.2",
|
|
48
|
+
"@getuserfeedback/sdk": "^0.8.33",
|
|
49
49
|
"robot3": "^1.2.0"
|
|
50
50
|
},
|
|
51
51
|
"peerDependencies": {
|