@getuserfeedback/react-native 4.0.12 → 4.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.
@@ -1,7 +1,8 @@
1
- import { createElement, Fragment, useCallback, useEffect, useMemo, useRef, useSyncExternalStore, } from "react";
1
+ import { createElement, Fragment, useCallback, useEffect, useLayoutEffect, useMemo, useRef, useSyncExternalStore, } from "react";
2
2
  import { NativeViewPresentationSurface } from "./native-view-presentation-surface.js";
3
3
  import { ViewWebViewHost } from "./view-webview-host.js";
4
4
  function NativeViewHostProjectionEntry({ controller, nativeViewComponent, onInvalidMessage, record, webViewComponent, webViewProps, }) {
5
+ var _a;
5
6
  const detachConnectionRef = useRef(null);
6
7
  const detachConnection = useCallback(() => {
7
8
  const detach = detachConnectionRef.current;
@@ -18,6 +19,24 @@ function NativeViewHostProjectionEntry({ controller, nativeViewComponent, onInva
18
19
  }
19
20
  }, [controller, record.allocationId]);
20
21
  const presentedWebViewProps = useMemo(() => (Object.assign(Object.assign({}, webViewProps), { style: [webViewProps === null || webViewProps === void 0 ? void 0 : webViewProps.style, { flex: 1 }] })), [webViewProps]);
22
+ const layoutTransactionId = (_a = record.size) === null || _a === void 0 ? void 0 : _a.layoutTransactionId;
23
+ useLayoutEffect(() => {
24
+ if (!layoutTransactionId) {
25
+ return;
26
+ }
27
+ controller.commitViewLayoutTransaction({
28
+ allocationId: record.allocationId,
29
+ layoutReportRevision: record.layoutReportRevision,
30
+ layoutTransactionId,
31
+ viewId: record.viewId,
32
+ });
33
+ }, [
34
+ controller,
35
+ layoutTransactionId,
36
+ record.allocationId,
37
+ record.layoutReportRevision,
38
+ record.viewId,
39
+ ]);
21
40
  useEffect(() => detachConnection, [detachConnection]);
22
41
  return createElement(NativeViewPresentationSurface, { nativeViewComponent, record }, createElement(ViewWebViewHost, {
23
42
  generation: record.generation,
@@ -28,7 +28,7 @@ const PREPARING_VIEW_FRAME_STYLE = {
28
28
  height: "100%",
29
29
  width: "100%",
30
30
  };
31
- const PRESENTED_VIEW_FRAME_STYLE = {
31
+ const MEASURED_VIEW_FRAME_STYLE = {
32
32
  maxHeight: "100%",
33
33
  maxWidth: "100%",
34
34
  };
@@ -51,16 +51,17 @@ const resolveNativeView = () => {
51
51
  return reactNativeModule.View;
52
52
  };
53
53
  export function NativeViewPresentationSurface({ children, nativeViewComponent, record, }) {
54
- var _a, _b, _c, _d, _e, _f, _g, _h;
54
+ var _a, _b, _c, _d, _e, _f, _g, _h, _j;
55
55
  const NativeView = nativeViewComponent !== null && nativeViewComponent !== void 0 ? nativeViewComponent : resolveNativeView();
56
56
  const isPresented = record.isActive && record.size !== null;
57
- const cornerRadii = toNativeWidgetCornerRadii((_a = record.size) === null || _a === void 0 ? void 0 : _a.frameAppearance);
58
- const shadow = toNativeWidgetFrameShadow(((_c = (_b = record.size) === null || _b === void 0 ? void 0 : _b.frameAppearance) === null || _c === void 0 ? void 0 : _c.kind) === "page"
57
+ const hasMeasuredFrame = isPresented || ((_a = record.size) === null || _a === void 0 ? void 0 : _a.layoutTransactionId) !== undefined;
58
+ const cornerRadii = toNativeWidgetCornerRadii((_b = record.size) === null || _b === void 0 ? void 0 : _b.frameAppearance);
59
+ const shadow = toNativeWidgetFrameShadow(((_d = (_c = record.size) === null || _c === void 0 ? void 0 : _c.frameAppearance) === null || _d === void 0 ? void 0 : _d.kind) === "page"
59
60
  ? record.size.frameAppearance.resolvedBoxShadow
60
61
  : undefined);
61
62
  const nativeBoxShadow = toNativeWidgetSupportedBoxShadow(shadow, resolveNativeWidgetBoxShadowSupport());
62
63
  const frameOverlayShadowStyle = nativeBoxShadow === undefined ? {} : { boxShadow: nativeBoxShadow };
63
- const borderStyle = toNativeWidgetResolvedBorderStyle(((_e = (_d = record.size) === null || _d === void 0 ? void 0 : _d.frameAppearance) === null || _e === void 0 ? void 0 : _e.kind) === "page"
64
+ const borderStyle = toNativeWidgetResolvedBorderStyle(((_f = (_e = record.size) === null || _e === void 0 ? void 0 : _e.frameAppearance) === null || _f === void 0 ? void 0 : _f.kind) === "page"
64
65
  ? record.size.frameAppearance.resolvedBorder
65
66
  : undefined);
66
67
  const cornerRadiusStyle = {
@@ -71,7 +72,7 @@ export function NativeViewPresentationSurface({ children, nativeViewComponent, r
71
72
  };
72
73
  return createElement(NativeView, {
73
74
  pointerEvents: isPresented ? "box-none" : "none",
74
- style: Object.assign(Object.assign(Object.assign({}, HOST_SURFACE_STYLE), (((_f = record.size) === null || _f === void 0 ? void 0 : _f.placement) === "docked-top"
75
+ style: Object.assign(Object.assign(Object.assign({}, HOST_SURFACE_STYLE), (((_g = record.size) === null || _g === void 0 ? void 0 : _g.placement) === "docked-top"
75
76
  ? TOP_PLACEMENT_STYLE
76
77
  : BOTTOM_PLACEMENT_STYLE)), (isPresented
77
78
  ? PRESENTED_HOST_SURFACE_STYLE
@@ -79,8 +80,8 @@ export function NativeViewPresentationSurface({ children, nativeViewComponent, r
79
80
  testID: `gx-native-view-presentation-${record.viewId}`,
80
81
  }, createElement(NativeView, {
81
82
  pointerEvents: isPresented ? "auto" : "none",
82
- style: isPresented
83
- ? Object.assign(Object.assign(Object.assign({}, PRESENTED_VIEW_FRAME_STYLE), cornerRadiusStyle), { height: (_g = record.size) === null || _g === void 0 ? void 0 : _g.height, width: (_h = record.size) === null || _h === void 0 ? void 0 : _h.width }) : PREPARING_VIEW_FRAME_STYLE,
83
+ style: hasMeasuredFrame
84
+ ? Object.assign(Object.assign(Object.assign({}, MEASURED_VIEW_FRAME_STYLE), cornerRadiusStyle), { height: (_h = record.size) === null || _h === void 0 ? void 0 : _h.height, width: (_j = record.size) === null || _j === void 0 ? void 0 : _j.width }) : PREPARING_VIEW_FRAME_STYLE,
84
85
  testID: `gx-native-view-frame-${record.viewId}`,
85
86
  }, createElement(NativeView, {
86
87
  style: Object.assign(Object.assign({}, VIEW_FRAME_CONTENT_STYLE), cornerRadiusStyle),
@@ -8,6 +8,7 @@ export type NativeViewRecord = Readonly<{
8
8
  generation: number;
9
9
  instanceId: string;
10
10
  isActive: boolean;
11
+ layoutReportRevision: number;
11
12
  openRequest: Readonly<OpenRequestMetadata> | undefined;
12
13
  size: NativeViewSizeReport | null;
13
14
  srcdoc: string;
@@ -18,6 +19,12 @@ export type NativeViewRecordController = {
18
19
  allocationId: number;
19
20
  connection: ViewWebViewHostConnection;
20
21
  }): (() => void) | null;
22
+ commitViewLayoutTransaction(input: {
23
+ allocationId: number;
24
+ layoutReportRevision: number;
25
+ layoutTransactionId: string;
26
+ viewId: string;
27
+ }): void;
21
28
  dispose(): void;
22
29
  getSnapshot(): readonly NativeViewRecord[];
23
30
  subscribe(listener: () => void): () => void;
@@ -1,5 +1,5 @@
1
1
  import { coreViewHostActionSchema, } from "@getuserfeedback/protocol/internal/core-view-host-actions";
2
- import { actionRequestCloseViewSchema, buildEventViewSize, eventViewSizeSchema, } from "@getuserfeedback/protocol/internal/view-host-control-messages";
2
+ import { actionRequestCloseViewSchema, buildEventLayoutTransactionCommitted, buildEventViewSize, eventViewSizeSchema, } from "@getuserfeedback/protocol/internal/view-host-control-messages";
3
3
  import { buildEventViewClosed, buildEventViewPrerendered, } from "@getuserfeedback/protocol/internal/view-host-lifecycle-events";
4
4
  import { createViewPreparationReadinessRegistry, createViewPreparationRegistry, } from "./view-orchestration-runtime.js";
5
5
  const createNativeViewReadinessRegistry = () => createViewPreparationReadinessRegistry();
@@ -51,6 +51,9 @@ export function createNativeViewRecordController(input) {
51
51
  return true;
52
52
  };
53
53
  const closeEntry = (entry) => {
54
+ if (entries.get(entry.viewId) !== entry) {
55
+ return;
56
+ }
54
57
  if (!preparations.cancel(entry.viewId)) {
55
58
  removeEntry(entry);
56
59
  }
@@ -69,11 +72,15 @@ export function createNativeViewRecordController(input) {
69
72
  generation: action.gen,
70
73
  instanceId: action.instanceId,
71
74
  isActive: false,
75
+ isClosing: false,
72
76
  isPreparationCommitted: false,
77
+ layoutReportRevision: 0,
73
78
  openRequest: toOpenRequestMetadata(action.openRequest),
74
79
  preparation,
75
80
  size: null,
76
81
  srcdoc: action.srcdoc,
82
+ committedLayoutReportOccurrence: null,
83
+ viewConnection: null,
77
84
  viewReadinessDetach: null,
78
85
  viewId: action.viewId,
79
86
  };
@@ -140,6 +147,10 @@ export function createNativeViewRecordController(input) {
140
147
  }));
141
148
  };
142
149
  const closeViewFromRequest = (entry, request) => {
150
+ if (entry.isClosing) {
151
+ return;
152
+ }
153
+ entry.isClosing = true;
143
154
  try {
144
155
  input.coreConnection.transport.postMessage(Object.assign(Object.assign({}, request), { viewId: entry.viewId }));
145
156
  input.coreConnection.transport.postMessage(buildEventViewClosed({
@@ -161,6 +172,39 @@ export function createNativeViewRecordController(input) {
161
172
  };
162
173
  const stopCoreTransport = input.coreConnection.transport.subscribe(handleCoreMessage);
163
174
  return {
175
+ commitViewLayoutTransaction({ allocationId, layoutReportRevision, layoutTransactionId, viewId, }) {
176
+ var _a, _b;
177
+ if (coreConnectionFailed || disposed) {
178
+ return;
179
+ }
180
+ const entry = entries.get(viewId);
181
+ const connection = entry === null || entry === void 0 ? void 0 : entry.viewConnection;
182
+ if (!entry ||
183
+ entry.allocationId !== allocationId ||
184
+ !connection ||
185
+ entry.layoutReportRevision !== layoutReportRevision ||
186
+ ((_a = entry.size) === null || _a === void 0 ? void 0 : _a.layoutTransactionId) !== layoutTransactionId ||
187
+ (((_b = entry.committedLayoutReportOccurrence) === null || _b === void 0 ? void 0 : _b.layoutReportRevision) ===
188
+ layoutReportRevision &&
189
+ entry.committedLayoutReportOccurrence.layoutTransactionId ===
190
+ layoutTransactionId)) {
191
+ return;
192
+ }
193
+ entry.committedLayoutReportOccurrence = {
194
+ layoutReportRevision,
195
+ layoutTransactionId,
196
+ };
197
+ try {
198
+ connection.transport.postMessage(buildEventLayoutTransactionCommitted({
199
+ gen: entry.generation,
200
+ layoutTransactionId,
201
+ viewId,
202
+ }));
203
+ }
204
+ catch (error) {
205
+ failCoreConnection(error, "Native view layout commit delivery failed");
206
+ }
207
+ },
164
208
  attachViewReadinessConnection({ allocationId, connection }) {
165
209
  if (coreConnectionFailed || disposed) {
166
210
  return null;
@@ -187,6 +231,8 @@ export function createNativeViewRecordController(input) {
187
231
  connectionReadiness.release();
188
232
  if (entry.viewReadinessDetach === detach) {
189
233
  entry.viewReadinessDetach = null;
234
+ entry.viewConnection = null;
235
+ entry.committedLayoutReportOccurrence = null;
190
236
  if (entry.size !== null) {
191
237
  entry.size = null;
192
238
  if (!disposed && entries.get(viewId) === entry) {
@@ -235,6 +281,7 @@ export function createNativeViewRecordController(input) {
235
281
  }
236
282
  const size = toViewSizeReport(parsed.data);
237
283
  entry.size = size;
284
+ entry.layoutReportRevision += 1;
238
285
  const readySize = connectionReadiness.recordSize(size);
239
286
  if (readySize) {
240
287
  deliverReadiness(readySize);
@@ -267,6 +314,8 @@ export function createNativeViewRecordController(input) {
267
314
  return null;
268
315
  }
269
316
  entry.viewReadinessDetach = detach;
317
+ entry.viewConnection = connection;
318
+ entry.committedLayoutReportOccurrence = null;
270
319
  previousDetach === null || previousDetach === void 0 ? void 0 : previousDetach();
271
320
  if (entry.size !== null) {
272
321
  entry.size = null;
@@ -320,6 +369,7 @@ function toRecord(entry) {
320
369
  generation: entry.generation,
321
370
  instanceId: entry.instanceId,
322
371
  isActive: entry.isActive,
372
+ layoutReportRevision: entry.layoutReportRevision,
323
373
  openRequest: entry.openRequest,
324
374
  size: entry.size,
325
375
  srcdoc: entry.srcdoc,
@@ -354,6 +404,7 @@ function toViewSizeReport(event) {
354
404
  width: event.width,
355
405
  height: event.height,
356
406
  intrinsicWidth: event.intrinsicWidth,
407
+ viewportRevision: event.viewportRevision,
357
408
  frameAppearance: event.frameAppearance,
358
409
  placement: event.placement,
359
410
  transitionPolicy: event.transitionPolicy,
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 : "4.0.12";
6
+ export const REACT_NATIVE_SDK_VERSION = reactNativeSdkVersion.length > 0 ? reactNativeSdkVersion : "4.0.20";
@@ -81,6 +81,7 @@ const buildViewHostBootstrapScript = () => {
81
81
  width: measurement.width,
82
82
  height: measurement.height,
83
83
  intrinsicWidth: measurement.intrinsicWidth,
84
+ viewportRevision: measurement.viewportRevision,
84
85
  frameAppearance: measurement.frameAppearance,
85
86
  placement: measurement.placement,
86
87
  transitionPolicy: measurement.transitionPolicy,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@getuserfeedback/react-native",
3
- "version": "4.0.12",
3
+ "version": "4.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.25.2",
48
- "@getuserfeedback/sdk": "^0.12.14",
47
+ "@getuserfeedback/protocol": "^3.30.1",
48
+ "@getuserfeedback/sdk": "^0.12.20",
49
49
  "robot3": "^1.2.0"
50
50
  },
51
51
  "peerDependencies": {