@getuserfeedback/react-native 2.0.19 → 2.0.20

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/dist/index.js CHANGED
@@ -9,7 +9,7 @@ var __rest = (this && this.__rest) || function (s, e) {
9
9
  }
10
10
  return t;
11
11
  };
12
- import { assertNoSegmentExternalIdsInValueArgument, CommandSettlementError, CommandSettlementTimeoutError, createFlowCommandHandleController, getFlowHandleFromSettlementDetail, getWidgetLayoutPlanNowMs, } from "@getuserfeedback/protocol/host";
12
+ import { assertNoSegmentExternalIdsInValueArgument, CommandSettlementError, CommandSettlementTimeoutError, createFlowCommandHandleController, getFlowHandleFromSettlementDetail, getWidgetLayoutPlanNowMs, REACT_NATIVE_WEBVIEW_TRANSPORT_CAPABILITIES, } from "@getuserfeedback/protocol/host";
13
13
  import { parseWebViewTransportNativeMessage } from "@getuserfeedback/protocol/webview-transport";
14
14
  import { createContext, createElement, useCallback, useContext, useEffect, useMemo, useRef, useState, } from "react";
15
15
  import { useResolvedHostViewport } from "./host-viewport.js";
@@ -126,6 +126,9 @@ const CLIENT_META = {
126
126
  clientName: "@getuserfeedback/react-native",
127
127
  clientVersion: REACT_NATIVE_SDK_VERSION,
128
128
  loader: "sdk",
129
+ protocolCapabilities: [
130
+ REACT_NATIVE_WEBVIEW_TRANSPORT_CAPABILITIES.LAYOUT_TRANSITION_POLICY,
131
+ ],
129
132
  transport: "loader",
130
133
  };
131
134
  const createUniqueId = (prefix) => {
@@ -607,6 +610,7 @@ export function GetUserFeedbackProvider({ autoInit = true, children, commandTime
607
610
  handleWebMessage,
608
611
  }), [enqueueCommand, flow, getNativeMessages, handleWebMessage, instanceId]);
609
612
  const previousSheetHostLayoutUpdateRef = useRef(undefined);
613
+ const consumedTransitionPolicySequenceRef = useRef(undefined);
610
614
  useEffect(() => {
611
615
  resetStartupQueuedKeyIfChanged(startupOptionsKey);
612
616
  enqueueStartupCommands();
@@ -616,6 +620,11 @@ export function GetUserFeedbackProvider({ autoInit = true, children, commandTime
616
620
  startupOptionsKey,
617
621
  ]);
618
622
  const providerHostViewport = hostViewport !== null && hostViewport !== void 0 ? hostViewport : resolvedHostViewport;
623
+ const transitionPolicySequence = widgetHostVisibility.transitionPolicySequence;
624
+ const pendingTransitionPolicy = transitionPolicySequence !== undefined &&
625
+ consumedTransitionPolicySequenceRef.current !== transitionPolicySequence
626
+ ? widgetHostVisibility.transitionPolicy
627
+ : undefined;
619
628
  const sheetHostLayoutPlan = toProviderWidgetSheetHostLayoutPlan({
620
629
  previous: previousSheetHostLayoutUpdateRef.current,
621
630
  viewport: providerHostViewport,
@@ -623,7 +632,15 @@ export function GetUserFeedbackProvider({ autoInit = true, children, commandTime
623
632
  height: widgetHostVisibility.flowHeight,
624
633
  },
625
634
  nowMs: getWidgetLayoutPlanNowMs(),
635
+ transitionPolicy: pendingTransitionPolicy,
626
636
  });
637
+ useEffect(() => {
638
+ if (transitionPolicySequence !== undefined &&
639
+ pendingTransitionPolicy !== undefined &&
640
+ sheetHostLayoutPlan !== undefined) {
641
+ consumedTransitionPolicySequenceRef.current = transitionPolicySequence;
642
+ }
643
+ }, [pendingTransitionPolicy, sheetHostLayoutPlan, transitionPolicySequence]);
627
644
  let sheetHostLayoutUpdate;
628
645
  if (sheetHostLayoutPlan) {
629
646
  switch (sheetHostLayoutPlan.kind) {
@@ -631,7 +648,17 @@ export function GetUserFeedbackProvider({ autoInit = true, children, commandTime
631
648
  sheetHostLayoutUpdate =
632
649
  (_a = previousSheetHostLayoutUpdateRef.current) !== null && _a !== void 0 ? _a : sheetHostLayoutPlan.update;
633
650
  break;
634
- case "instant":
651
+ case "instant": {
652
+ const previousSheetHostLayoutUpdate = previousSheetHostLayoutUpdateRef.current;
653
+ sheetHostLayoutUpdate =
654
+ pendingTransitionPolicy === undefined &&
655
+ (previousSheetHostLayoutUpdate === null || previousSheetHostLayoutUpdate === void 0 ? void 0 : previousSheetHostLayoutUpdate.transition.kind) === "timed" &&
656
+ previousSheetHostLayoutUpdate.size.height ===
657
+ sheetHostLayoutPlan.size.height
658
+ ? previousSheetHostLayoutUpdate
659
+ : sheetHostLayoutPlan.update;
660
+ break;
661
+ }
635
662
  case "timed":
636
663
  sheetHostLayoutUpdate = sheetHostLayoutPlan.update;
637
664
  break;
@@ -1,3 +1,4 @@
1
+ import { type WidgetLayoutTransitionPolicy } from "@getuserfeedback/protocol/host";
1
2
  type ProviderWidgetHostReadyState = {
2
3
  hostEpoch: number;
3
4
  readySequence: number;
@@ -10,6 +11,8 @@ export type ProviderWidgetHostVisibility = {
10
11
  isVisible: boolean;
11
12
  readySequence: number | null;
12
13
  sourceKey: string | null;
14
+ transitionPolicy?: WidgetLayoutTransitionPolicy;
15
+ transitionPolicySequence?: number;
13
16
  };
14
17
  type ProviderWidgetHostFlowState = {
15
18
  height?: number;
@@ -18,6 +21,7 @@ type ProviderWidgetHostFlowState = {
18
21
  isLoading: boolean;
19
22
  isOpen: boolean;
20
23
  shouldRender?: boolean;
24
+ transitionPolicy?: WidgetLayoutTransitionPolicy;
21
25
  width?: number;
22
26
  };
23
27
  type ProviderWidgetHostSnapshot = {
@@ -26,6 +30,7 @@ type ProviderWidgetHostSnapshot = {
26
30
  isLoading: boolean;
27
31
  isOpen: boolean;
28
32
  shouldRender: boolean;
33
+ transitionPolicy?: WidgetLayoutTransitionPolicy;
29
34
  width?: number;
30
35
  };
31
36
  export declare const HIDDEN_PROVIDER_WIDGET_HOST_VISIBILITY: ProviderWidgetHostVisibility;
@@ -1,4 +1,4 @@
1
- import { resolveInstanceFlowStateShouldRender } from "@getuserfeedback/protocol/host";
1
+ import { resolveInstanceFlowStateShouldRender, } from "@getuserfeedback/protocol/host";
2
2
  export const HIDDEN_PROVIDER_WIDGET_HOST_VISIBILITY = {
3
3
  hostSourceVersion: null,
4
4
  isVisible: false,
@@ -15,6 +15,7 @@ export function toProviderWidgetHostSnapshot(detail, instanceId) {
15
15
  isLoading: detail.isLoading,
16
16
  isOpen: detail.isOpen,
17
17
  shouldRender: resolveInstanceFlowStateShouldRender(detail),
18
+ transitionPolicy: detail.transitionPolicy,
18
19
  width: detail.width,
19
20
  };
20
21
  return snapshot;
@@ -24,6 +25,7 @@ export function createProviderWidgetHostLifecycleController(initialHostSourceKey
24
25
  let hostSourceKey = initialHostSourceKey;
25
26
  let hostSourceVersion = 0;
26
27
  let lastReady = null;
28
+ let transitionPolicySequence = 0;
27
29
  return {
28
30
  clearFlowHandleFromVisibility: (visibility, flowHandleId) => visibility.flowHandleId === flowHandleId
29
31
  ? Object.assign(Object.assign({}, visibility), { flowHandleId: undefined }) : visibility,
@@ -76,6 +78,11 @@ export function createProviderWidgetHostLifecycleController(initialHostSourceKey
76
78
  if (lastReady === null) {
77
79
  return null;
78
80
  }
81
+ let nextTransitionPolicySequence;
82
+ if (snapshot.transitionPolicy !== undefined) {
83
+ transitionPolicySequence += 1;
84
+ nextTransitionPolicySequence = transitionPolicySequence;
85
+ }
79
86
  return {
80
87
  flowHeight: snapshot.height,
81
88
  flowHandleId: snapshot.flowHandleId,
@@ -83,6 +90,8 @@ export function createProviderWidgetHostLifecycleController(initialHostSourceKey
83
90
  isVisible: snapshot.shouldRender,
84
91
  readySequence: lastReady.readySequence,
85
92
  sourceKey: lastReady.sourceKey,
93
+ transitionPolicy: snapshot.transitionPolicy,
94
+ transitionPolicySequence: nextTransitionPolicySequence,
86
95
  };
87
96
  },
88
97
  toReadyVisibility: (visibility, event) => {
@@ -1,5 +1,5 @@
1
1
  import { planWidgetLayoutTransition, toInstantWidgetLayoutSizeUpdate, } from "@getuserfeedback/protocol/host";
2
- import { createElement, useCallback, useMemo, useRef, } from "react";
2
+ import { createElement, useCallback, useEffect, useMemo, useRef, } from "react";
3
3
  const HIDDEN_WIDGET_HOST_STYLE = {
4
4
  bottom: 0,
5
5
  left: 0,
@@ -101,6 +101,20 @@ function resolveNativePanResponder() {
101
101
  return null;
102
102
  }
103
103
  }
104
+ function resolveNativeAnimationRuntime() {
105
+ try {
106
+ const reactNativeModule = require("react-native");
107
+ return reactNativeModule.Animated
108
+ ? {
109
+ Animated: reactNativeModule.Animated,
110
+ Easing: reactNativeModule.Easing,
111
+ }
112
+ : null;
113
+ }
114
+ catch (_a) {
115
+ return null;
116
+ }
117
+ }
104
118
  function toResponderPageY(event) {
105
119
  var _a, _b, _c;
106
120
  const nativeEvent = event === null || event === void 0 ? void 0 : event.nativeEvent;
@@ -182,6 +196,87 @@ export function toProviderWidgetSheetStyle(input) {
182
196
  return input.isVisible && sheetHostViewport !== undefined
183
197
  ? Object.assign(Object.assign({}, WIDGET_SHEET_STYLE), { height: sheetHostViewport.height }) : HIDDEN_WIDGET_HOST_STYLE;
184
198
  }
199
+ function useProviderWidgetSheetPresentation(input) {
200
+ var _a, _b, _c, _d;
201
+ const animationRuntime = useMemo(resolveNativeAnimationRuntime, []);
202
+ const animatedHeightRef = useRef(null);
203
+ const animationRef = useRef(null);
204
+ const previousHeightRef = useRef(undefined);
205
+ const animatedSheetView = useMemo(() => animationRuntime
206
+ ? animationRuntime.Animated.createAnimatedComponent(input.nativeView)
207
+ : input.nativeView, [animationRuntime, input.nativeView]);
208
+ const staticStyle = toProviderWidgetSheetStyle({
209
+ isVisible: input.isVisible,
210
+ sheetHostLayoutUpdate: input.sheetHostLayoutUpdate,
211
+ });
212
+ const sheetHostViewport = (_a = input.sheetHostLayoutUpdate) === null || _a === void 0 ? void 0 : _a.size;
213
+ const height = sheetHostViewport === null || sheetHostViewport === void 0 ? void 0 : sheetHostViewport.height;
214
+ const shouldUseAnimatedStyle = animationRuntime !== null &&
215
+ input.isVisible &&
216
+ height !== undefined &&
217
+ ((_b = input.sheetHostLayoutUpdate) === null || _b === void 0 ? void 0 : _b.transition.kind) === "timed";
218
+ const sheetView = animationRuntime ? animatedSheetView : input.nativeView;
219
+ if (animationRuntime &&
220
+ height !== undefined &&
221
+ animatedHeightRef.current === null) {
222
+ animatedHeightRef.current = new animationRuntime.Animated.Value(height);
223
+ }
224
+ useEffect(() => {
225
+ var _a, _b, _c, _d, _e, _f;
226
+ if (!animationRuntime || height === undefined) {
227
+ (_b = (_a = animationRef.current) === null || _a === void 0 ? void 0 : _a.stop) === null || _b === void 0 ? void 0 : _b.call(_a);
228
+ animationRef.current = null;
229
+ previousHeightRef.current = height;
230
+ return;
231
+ }
232
+ const animatedHeight = animatedHeightRef.current;
233
+ if (!animatedHeight) {
234
+ return;
235
+ }
236
+ const previousHeight = previousHeightRef.current;
237
+ previousHeightRef.current = height;
238
+ const transition = (_c = input.sheetHostLayoutUpdate) === null || _c === void 0 ? void 0 : _c.transition;
239
+ const activeAnimation = animationRef.current;
240
+ (_d = activeAnimation === null || activeAnimation === void 0 ? void 0 : activeAnimation.stop) === null || _d === void 0 ? void 0 : _d.call(activeAnimation);
241
+ animationRef.current = null;
242
+ if (previousHeight === undefined || (transition === null || transition === void 0 ? void 0 : transition.kind) !== "timed") {
243
+ animatedHeight.setValue(height);
244
+ return;
245
+ }
246
+ if (previousHeight === height && !activeAnimation) {
247
+ animatedHeight.setValue(height);
248
+ return;
249
+ }
250
+ const easing = transition.easing.kind === "cubic-bezier"
251
+ ? (_f = (_e = animationRuntime.Easing) === null || _e === void 0 ? void 0 : _e.bezier) === null || _f === void 0 ? void 0 : _f.call(_e, ...transition.easing.points)
252
+ : undefined;
253
+ const animation = animationRuntime.Animated.timing(animatedHeight, {
254
+ toValue: height,
255
+ duration: transition.durationMs,
256
+ easing,
257
+ useNativeDriver: false,
258
+ });
259
+ animationRef.current = animation;
260
+ animation.start();
261
+ return () => {
262
+ var _a;
263
+ (_a = animation.stop) === null || _a === void 0 ? void 0 : _a.call(animation);
264
+ if (animationRef.current === animation) {
265
+ animationRef.current = null;
266
+ }
267
+ };
268
+ }, [animationRuntime, height, (_c = input.sheetHostLayoutUpdate) === null || _c === void 0 ? void 0 : _c.transition]);
269
+ if (!shouldUseAnimatedStyle) {
270
+ return {
271
+ sheetView,
272
+ style: staticStyle,
273
+ };
274
+ }
275
+ return {
276
+ sheetView,
277
+ style: Object.assign(Object.assign({}, staticStyle), { height: (_d = animatedHeightRef.current) !== null && _d !== void 0 ? _d : height }),
278
+ };
279
+ }
185
280
  export function ProviderWidgetHostOverlay({ children, isVisible, nativeView, onRequestDismiss, sheetHostLayoutUpdate, }) {
186
281
  const dragStartYRef = useRef(undefined);
187
282
  const handleDragGrant = useCallback((event) => {
@@ -236,6 +331,11 @@ export function ProviderWidgetHostOverlay({ children, isVisible, nativeView, onR
236
331
  const sheetHostViewport = sheetHostLayoutUpdate === null || sheetHostLayoutUpdate === void 0 ? void 0 : sheetHostLayoutUpdate.size;
237
332
  const isSheetVisible = isVisible && sheetHostViewport !== undefined;
238
333
  const pointerEvents = isSheetVisible ? "auto" : "none";
334
+ const sheetPresentation = useProviderWidgetSheetPresentation({
335
+ isVisible,
336
+ nativeView,
337
+ sheetHostLayoutUpdate,
338
+ });
239
339
  return createElement(nativeView, {
240
340
  pointerEvents,
241
341
  style: isSheetVisible
@@ -248,12 +348,9 @@ export function ProviderWidgetHostOverlay({ children, isVisible, nativeView, onR
248
348
  ? WIDGET_SHEET_BACKDROP_STYLE
249
349
  : HIDDEN_WIDGET_HOST_STYLE,
250
350
  testID: "gx-widget-host-backdrop",
251
- }), createElement(nativeView, {
351
+ }), createElement(sheetPresentation.sheetView, {
252
352
  pointerEvents,
253
- style: toProviderWidgetSheetStyle({
254
- isVisible,
255
- sheetHostLayoutUpdate,
256
- }),
353
+ style: sheetPresentation.style,
257
354
  testID: "gx-widget-host-sheet",
258
355
  }, children, isSheetVisible
259
356
  ? createElement(nativeView, Object.assign(Object.assign({}, dragHandleGestureProps), { style: WIDGET_SHEET_DRAG_HANDLE_TOUCH_STYLE, testID: "gx-widget-host-drag-handle" }), createElement(nativeView, {
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 : "2.0.19";
6
+ export const REACT_NATIVE_SDK_VERSION = reactNativeSdkVersion.length > 0 ? reactNativeSdkVersion : "2.0.20";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@getuserfeedback/react-native",
3
- "version": "2.0.19",
3
+ "version": "2.0.20",
4
4
  "description": "getuserfeedback React Native SDK",
5
5
  "keywords": [
6
6
  "getuserfeedback",
@@ -44,8 +44,8 @@
44
44
  "lint": "biome check ."
45
45
  },
46
46
  "dependencies": {
47
- "@getuserfeedback/protocol": "^3.1.7",
48
- "@getuserfeedback/sdk": "^0.8.24",
47
+ "@getuserfeedback/protocol": "^3.1.8",
48
+ "@getuserfeedback/sdk": "^0.8.25",
49
49
  "robot3": "^1.2.0"
50
50
  },
51
51
  "peerDependencies": {