@uptick-ads/react-native-web-sdk 0.2.6 → 0.2.7
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 +2 -2
- package/index.d.ts +4 -1
- package/package.json +2 -2
- package/src/UptickFlow.js +8 -6
- package/src/embedUrl.js +19 -2
- package/src/index.js +2 -1
- package/src/version.js +2 -0
package/README.md
CHANGED
|
@@ -38,7 +38,7 @@ import { UptickFlow } from "@uptick-ads/react-native-web-sdk";
|
|
|
38
38
|
|
|
39
39
|
Whether the offer renders inline or as a popup is configured by the Uptick offers team on your placement, not in your app.
|
|
40
40
|
When the placement is inline, the component sizes itself to the offer and starts at zero height, so nothing shows until an offer is ready.
|
|
41
|
-
When the placement is a popup, the component presents a modal over the whole screen with a
|
|
41
|
+
When the placement is a popup, the component presents a modal over the whole screen with a dimmed background and a centred card, from wherever it is mounted. Tap outside, the card's close button, and the Android back button all dismiss it.
|
|
42
42
|
Because both presentations work from the same mount point, Uptick can switch a placement between inline and popup without a change to your app.
|
|
43
43
|
|
|
44
44
|
## Props
|
|
@@ -50,7 +50,7 @@ Because both presentations work from the same mount point, Uptick can switch a p
|
|
|
50
50
|
| `callback` | | `(event, data)`, the same events as the web SDK callback |
|
|
51
51
|
| `openUrl` | `Linking.openURL` | How accepted offers open; supply your own to use an in-app browser |
|
|
52
52
|
| `style` | | Style for the inline slot |
|
|
53
|
-
| `modal` | |
|
|
53
|
+
| `modal` | | Presentation options for the popup. Any option set here is reported to Uptick with the flow so performance can be read against it. |
|
|
54
54
|
| `webViewProps` | | Extra props passed through to `WebView` |
|
|
55
55
|
| `host` | `api.uptick.com` | API host, only for testing against other environments |
|
|
56
56
|
|
package/index.d.ts
CHANGED
|
@@ -21,7 +21,8 @@ export interface UptickFlowParams {
|
|
|
21
21
|
}
|
|
22
22
|
|
|
23
23
|
export interface UptickModalOptions {
|
|
24
|
-
|
|
24
|
+
/** Colour of the dimmed layer behind the card. */
|
|
25
|
+
backgroundColor?: string;
|
|
25
26
|
cardStyle?: StyleProp<ViewStyle>;
|
|
26
27
|
insets?: { top: number; bottom: number };
|
|
27
28
|
maxCardHeight?: number;
|
|
@@ -40,6 +41,8 @@ export interface UptickFlowProps extends UptickFlowParams {
|
|
|
40
41
|
|
|
41
42
|
export function UptickFlow(props: UptickFlowProps): JSX.Element;
|
|
42
43
|
|
|
44
|
+
export const version: string;
|
|
45
|
+
export function integrationVersion(sdkVersion: string, modal?: UptickModalOptions): string;
|
|
43
46
|
export const FLOW_PARAMS: ReadonlyArray<keyof UptickFlowParams>;
|
|
44
47
|
export function pickFlowParams(props: Record<string, unknown>): UptickFlowParams;
|
|
45
48
|
export function buildEmbedUrl(options: { host: string; integrationId: string; placement?: string; params?: UptickFlowParams }): string;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@uptick-ads/react-native-web-sdk",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.7",
|
|
4
4
|
"description": "React Native component that runs the Uptick web SDK inside a WebView, inline or as a popup, with the web integration's parameters",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"uptick",
|
|
@@ -40,7 +40,7 @@
|
|
|
40
40
|
"provenance": false
|
|
41
41
|
},
|
|
42
42
|
"scripts": {
|
|
43
|
-
"check": "node --check src/index.js && node --check src/UptickFlow.js && node --check src/embedUrl.js && npm pack --dry-run",
|
|
43
|
+
"check": "node --check src/index.js && node --check src/UptickFlow.js && node --check src/embedUrl.js && node --check src/version.js && node -e \"const p=require('./package.json');const v=require('fs').readFileSync('src/version.js','utf8');if(!v.includes('\\\"'+p.version+'\\\"'))throw new Error('src/version.js is out of step with package.json')\" && npm pack --dry-run",
|
|
44
44
|
"prepublishOnly": "npm run check"
|
|
45
45
|
},
|
|
46
46
|
"private": false
|
package/src/UptickFlow.js
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import React, { useCallback, useEffect, useMemo, useRef, useState } from "react";
|
|
2
2
|
import { Linking, Modal, Pressable, StyleSheet, View } from "react-native";
|
|
3
3
|
import { WebView } from "react-native-webview";
|
|
4
|
-
import { buildEmbedUrl, embedPath, pickFlowParams } from "./embedUrl";
|
|
4
|
+
import { buildEmbedUrl, embedPath, integrationVersion, pickFlowParams } from "./embedUrl";
|
|
5
|
+
import { version as SDK_VERSION } from "./version";
|
|
5
6
|
|
|
6
7
|
const DEFAULT_HOST = "api.uptick.com";
|
|
7
8
|
const MAX_HEIGHT = 1400;
|
|
@@ -33,11 +34,12 @@ export function UptickFlow({
|
|
|
33
34
|
|
|
34
35
|
const params = pickFlowParams(flowProps);
|
|
35
36
|
const paramsKey = JSON.stringify(params);
|
|
37
|
+
const version = integrationVersion(SDK_VERSION, modal);
|
|
36
38
|
const source = useMemo(
|
|
37
|
-
() => ({ uri: buildEmbedUrl({ host, integrationId, placement, params }) }),
|
|
39
|
+
() => ({ uri: buildEmbedUrl({ host, integrationId, placement, params, version }) }),
|
|
38
40
|
// Callers pass fresh prop values each render; key on the serialised params so the page does not reload on every parent render.
|
|
39
41
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
40
|
-
[host, integrationId, placement, paramsKey]
|
|
42
|
+
[host, integrationId, placement, paramsKey, version]
|
|
41
43
|
);
|
|
42
44
|
const ownPath = embedPath(host, integrationId);
|
|
43
45
|
|
|
@@ -102,7 +104,7 @@ export function UptickFlow({
|
|
|
102
104
|
const isPopup = renderType === "popup";
|
|
103
105
|
const contentHeight = Math.max(height, 1);
|
|
104
106
|
const {
|
|
105
|
-
|
|
107
|
+
backgroundColor = "rgba(0, 0, 0, 0.45)",
|
|
106
108
|
cardStyle,
|
|
107
109
|
insets = { top: 24, bottom: 24 },
|
|
108
110
|
maxCardHeight = 620,
|
|
@@ -134,13 +136,13 @@ export function UptickFlow({
|
|
|
134
136
|
return <View style={[styles.transparent, { height: renderType === "inline" ? contentHeight : 1, overflow: "hidden" }, style]}>{webView}</View>;
|
|
135
137
|
}
|
|
136
138
|
|
|
137
|
-
// Popup: the page has already loaded inside the inline slot, so keep that WebView alive and move it into a system modal.
|
|
139
|
+
// Popup: the page has already loaded inside the inline slot, so keep that WebView alive and move it into a system modal over a dimmed background.
|
|
138
140
|
// React Native's Modal presents above the whole window regardless of where this component sits in the tree.
|
|
139
141
|
return (
|
|
140
142
|
<View style={[styles.transparent, { height: 0 }, style]}>
|
|
141
143
|
<Modal visible transparent animationType="fade" statusBarTranslucent onRequestClose={dismiss}>
|
|
142
144
|
<View style={FILL} pointerEvents={visible ? "auto" : "none"}>
|
|
143
|
-
<Pressable accessibilityRole="button" accessibilityLabel="Dismiss" style={[FILL, { backgroundColor
|
|
145
|
+
<Pressable accessibilityRole="button" accessibilityLabel="Dismiss" style={[FILL, { backgroundColor, opacity: visible ? 1 : 0 }]} onPress={dismiss} />
|
|
144
146
|
<View pointerEvents="box-none" style={[FILL, styles.cardWrap, { paddingTop: insets.top, paddingBottom: insets.bottom, opacity: visible ? 1 : 0 }]}>
|
|
145
147
|
<View style={[styles.card, { height: Math.min(contentHeight, maxCardHeight) }, cardStyle]}>{webView}</View>
|
|
146
148
|
</View>
|
package/src/embedUrl.js
CHANGED
|
@@ -41,10 +41,27 @@ export function embedPath(host, integrationId) {
|
|
|
41
41
|
return `https://${host}/v1/places/${encodeURIComponent(integrationId)}/embed`;
|
|
42
42
|
}
|
|
43
43
|
|
|
44
|
-
|
|
44
|
+
// Names of the presentation options a host customised, so reporting can tell a stock integration from a tuned one when performance differs.
|
|
45
|
+
export function customizations(modal) {
|
|
46
|
+
if (!modal) return [];
|
|
47
|
+
const names = [];
|
|
48
|
+
if (modal.backgroundColor !== undefined) names.push("background");
|
|
49
|
+
if (modal.cardStyle !== undefined) names.push("card");
|
|
50
|
+
if (modal.insets !== undefined) names.push("insets");
|
|
51
|
+
if (modal.maxCardHeight !== undefined) names.push("height");
|
|
52
|
+
return names;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
// The integration version the API records on every event; a `+custom.` suffix lists any presentation options the host changed.
|
|
56
|
+
export function integrationVersion(sdkVersion, modal) {
|
|
57
|
+
const names = customizations(modal);
|
|
58
|
+
return names.length ? `${sdkVersion}+custom.${names.join(",")}` : sdkVersion;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
export function buildEmbedUrl({ host, integrationId, placement, params, version }) {
|
|
45
62
|
if (!integrationId) throw new Error("UptickFlow: integrationId is required");
|
|
46
63
|
// The page renders whatever presentation the placement's template defines; `native` only asks it to leave the popup chrome to the app.
|
|
47
|
-
const search = encodeQuery({ placement, variant: "native" });
|
|
64
|
+
const search = encodeQuery({ placement, variant: "native", integration_version: version });
|
|
48
65
|
const fragment = encodeQuery(params || {});
|
|
49
66
|
return `${embedPath(host, integrationId)}?${search}${fragment ? `#${fragment}` : ""}`;
|
|
50
67
|
}
|
package/src/index.js
CHANGED
package/src/version.js
ADDED