rampkit-expo-dev 0.0.5 → 0.0.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 CHANGED
@@ -1,5 +1,6 @@
1
1
  <p align="center">
2
- <img src="https://dqplcvw3fzili.cloudfront.net/rampkitlogo.png" height="80" />
2
+ <br />
3
+ <img src="https://dqplcvw3fzili.cloudfront.net/rampkitlogo.png" height="110" />
3
4
  </p>
4
5
 
5
6
  <h1 align="center">RampKit Expo SDK</h1>
@@ -37,15 +38,20 @@ npx expo install rampkit-expo-dev
37
38
  ```ts
38
39
  import { RampKit } from "rampkit-expo-dev";
39
40
 
40
- RampKit.configure({
41
- projectId: "YOUR_PROJECT_ID",
41
+ await RampKit.init({
42
+ apiKey: "YOUR_API_KEY",
43
+ environment: "production", // optional
44
+ autoShowOnboarding: false, // optional
45
+ onOnboardingFinished: (payload) => {
46
+ // optional callback fired when the flow finishes
47
+ },
42
48
  });
43
49
  ```
44
50
 
45
51
  Show an onboarding:
46
52
 
47
53
  ```ts
48
- await RampKit.present();
54
+ RampKit.showOnboarding();
49
55
  ```
50
56
 
51
57
  ---
@@ -53,11 +59,21 @@ await RampKit.present();
53
59
  ## Configuration Options
54
60
 
55
61
  ```ts
56
- RampKit.configure({
57
- projectId: "abc123",
58
- userId: "user_42", // optional
59
- debug: true, // optional
62
+ await RampKit.init({
63
+ apiKey: "abc123",
64
+ environment: "staging", // optional
65
+ autoShowOnboarding: true, // optional (auto-present after init if data is available)
66
+ onOnboardingFinished: (payload) => {
67
+ // optional
68
+ },
60
69
  });
70
+
71
+ // Access the generated stable user id (stored securely)
72
+ const idFromInit = RampKit.getUserId(); // string | null (available after init)
73
+
74
+ // Or fetch/generate it directly (always returns a string)
75
+ import { getRampKitUserId } from "rampkit-expo-dev";
76
+ const userId = await getRampKitUserId();
61
77
  ```
62
78
 
63
79
  More examples are in the docs:
@@ -68,11 +84,19 @@ https://rampkit.com/docs
68
84
  ## Example
69
85
 
70
86
  ```ts
87
+ import { useEffect } from "react";
71
88
  import { RampKit } from "rampkit-expo-dev";
72
89
  import { Button } from "react-native";
73
90
 
74
91
  export default function App() {
75
- return <Button title="Show Onboarding" onPress={() => RampKit.present()} />;
92
+ useEffect(() => {
93
+ // Initialize once in your app
94
+ RampKit.init({ apiKey: "YOUR_API_KEY" });
95
+ }, []);
96
+
97
+ return (
98
+ <Button title="Show Onboarding" onPress={() => RampKit.showOnboarding()} />
99
+ );
76
100
  }
77
101
  ```
78
102
 
@@ -4,6 +4,7 @@ export declare class RampKitCore {
4
4
  private onboardingData;
5
5
  private userId;
6
6
  private onOnboardingFinished?;
7
+ private onShowPaywall?;
7
8
  private static readonly ONBOARDING_URL;
8
9
  static get instance(): RampKitCore;
9
10
  init(config: {
@@ -11,8 +12,11 @@ export declare class RampKitCore {
11
12
  environment?: string;
12
13
  autoShowOnboarding?: boolean;
13
14
  onOnboardingFinished?: (payload?: any) => void;
15
+ showPaywall?: () => void;
14
16
  }): Promise<void>;
15
17
  getOnboardingData(): any;
16
18
  getUserId(): string | null;
17
- showOnboarding(): void;
19
+ showOnboarding(opts?: {
20
+ showPaywall?: () => void;
21
+ }): void;
18
22
  }
package/build/RampKit.js CHANGED
@@ -17,6 +17,7 @@ class RampKitCore {
17
17
  async init(config) {
18
18
  this.config = config;
19
19
  this.onOnboardingFinished = config.onOnboardingFinished;
20
+ this.onShowPaywall = config.showPaywall;
20
21
  try {
21
22
  // Ensure a stable, encrypted user id exists on first init
22
23
  this.userId = await (0, userId_1.getRampKitUserId)();
@@ -56,7 +57,7 @@ class RampKitCore {
56
57
  getUserId() {
57
58
  return this.userId;
58
59
  }
59
- showOnboarding() {
60
+ showOnboarding(opts) {
60
61
  const data = this.onboardingData;
61
62
  if (!data || !Array.isArray(data.screens) || data.screens.length === 0) {
62
63
  console.log("[RampKit] ShowOnboarding: no onboarding data available");
@@ -109,6 +110,7 @@ class RampKitCore {
109
110
  }
110
111
  catch (_) { }
111
112
  },
113
+ onShowPaywall: (opts === null || opts === void 0 ? void 0 : opts.showPaywall) || this.onShowPaywall,
112
114
  });
113
115
  }
114
116
  catch (e) {
@@ -13,6 +13,7 @@ export declare function showRampkitOverlay(opts: {
13
13
  requiredScripts?: string[];
14
14
  onClose?: () => void;
15
15
  onOnboardingFinished?: (payload?: any) => void;
16
+ onShowPaywall?: () => void;
16
17
  }): void;
17
18
  export declare function hideRampkitOverlay(): void;
18
19
  export declare function preloadRampkitOverlay(opts: {
@@ -29,5 +30,6 @@ declare function Overlay(props: {
29
30
  prebuiltDocs?: string[];
30
31
  onRequestClose: () => void;
31
32
  onOnboardingFinished?: (payload?: any) => void;
33
+ onShowPaywall?: () => void;
32
34
  }): any;
33
35
  export default Overlay;
@@ -138,7 +138,7 @@ function showRampkitOverlay(opts) {
138
138
  var _a;
139
139
  hideRampkitOverlay();
140
140
  (_a = opts.onClose) === null || _a === void 0 ? void 0 : _a.call(opts);
141
- }, onOnboardingFinished: opts.onOnboardingFinished })));
141
+ }, onOnboardingFinished: opts.onOnboardingFinished, onShowPaywall: opts.onShowPaywall })));
142
142
  // Once shown, we can safely discard the preloader sibling if present
143
143
  if (preloadSibling) {
144
144
  preloadSibling.destroy();
@@ -235,6 +235,8 @@ function Overlay(props) {
235
235
  const [firstPageLoaded, setFirstPageLoaded] = (0, react_1.useState)(false);
236
236
  const [visible, setVisible] = (0, react_1.useState)(false);
237
237
  const [isTransitioning, setIsTransitioning] = (0, react_1.useState)(false);
238
+ const [isClosing, setIsClosing] = (0, react_1.useState)(false);
239
+ const overlayOpacity = (0, react_1.useRef)(new react_native_1.Animated.Value(0)).current;
238
240
  const fadeOpacity = (0, react_1.useRef)(new react_native_1.Animated.Value(0)).current;
239
241
  const allLoaded = loadedCount >= props.screens.length;
240
242
  // shared vars across all webviews
@@ -243,6 +245,39 @@ function Overlay(props) {
243
245
  const webviewsRef = (0, react_1.useRef)([]);
244
246
  // track when we last initialized a given page with host vars (to filter stale defaults)
245
247
  const lastInitSendRef = (0, react_1.useRef)([]);
248
+ // Fade-in when overlay becomes visible
249
+ react_1.default.useEffect(() => {
250
+ if (visible && !isClosing) {
251
+ try {
252
+ overlayOpacity.stopAnimation();
253
+ }
254
+ catch (_) { }
255
+ overlayOpacity.setValue(0);
256
+ react_native_1.Animated.timing(overlayOpacity, {
257
+ toValue: 1,
258
+ duration: 220,
259
+ easing: react_native_1.Easing.out(react_native_1.Easing.cubic),
260
+ useNativeDriver: true,
261
+ }).start();
262
+ }
263
+ }, [visible, isClosing, overlayOpacity]);
264
+ const handleRequestClose = react_1.default.useCallback(() => {
265
+ if (isClosing)
266
+ return;
267
+ setIsClosing(true);
268
+ try {
269
+ overlayOpacity.stopAnimation();
270
+ }
271
+ catch (_) { }
272
+ react_native_1.Animated.timing(overlayOpacity, {
273
+ toValue: 0,
274
+ duration: 220,
275
+ easing: react_native_1.Easing.out(react_native_1.Easing.cubic),
276
+ useNativeDriver: true,
277
+ }).start(() => {
278
+ props.onRequestClose();
279
+ });
280
+ }, [isClosing, overlayOpacity, props.onRequestClose]);
246
281
  // Android hardware back goes to previous page, then closes
247
282
  const navigateToIndex = (nextIndex) => {
248
283
  if (nextIndex === index ||
@@ -312,11 +347,11 @@ function Overlay(props) {
312
347
  navigateToIndex(index - 1);
313
348
  return true;
314
349
  }
315
- props.onRequestClose();
350
+ handleRequestClose();
316
351
  return true;
317
352
  });
318
353
  return () => sub.remove();
319
- }, [index, props.onRequestClose]);
354
+ }, [index, handleRequestClose]);
320
355
  const docs = (0, react_1.useMemo)(() => props.prebuiltDocs ||
321
356
  props.screens.map((s) => buildHtmlDocument(s, props.variables, props.requiredScripts)), [props.prebuiltDocs, props.screens, props.variables, props.requiredScripts]);
322
357
  react_1.default.useEffect(() => {
@@ -364,7 +399,7 @@ function Overlay(props) {
364
399
  else {
365
400
  // finish
366
401
  Haptics.notificationAsync(Haptics.NotificationFeedbackType.Success).catch(() => { });
367
- props.onRequestClose();
402
+ handleRequestClose();
368
403
  }
369
404
  };
370
405
  async function handleNotificationPermissionRequest(payload) {
@@ -451,7 +486,11 @@ function Overlay(props) {
451
486
  }
452
487
  catch (_) { }
453
488
  }
454
- return ((0, jsx_runtime_1.jsxs)(react_native_1.View, { style: [styles.root, !visible && styles.invisible], pointerEvents: visible ? "auto" : "none", children: [(0, jsx_runtime_1.jsx)(react_native_pager_view_1.default, { ref: pagerRef, style: react_native_1.StyleSheet.absoluteFill, scrollEnabled: false, initialPage: 0, onPageSelected: onPageSelected, offscreenPageLimit: props.screens.length, overScrollMode: "never", children: docs.map((doc, i) => ((0, jsx_runtime_1.jsx)(react_native_1.View, { style: styles.page, renderToHardwareTextureAndroid: true, children: (0, jsx_runtime_1.jsx)(react_native_webview_1.WebView, { ref: (r) => (webviewsRef.current[i] = r), style: styles.webview, originWhitelist: ["*"], source: { html: doc }, injectedJavaScriptBeforeContentLoaded: exports.injectedHardening, injectedJavaScript: exports.injectedNoSelect, automaticallyAdjustContentInsets: false, contentInsetAdjustmentBehavior: "never", bounces: false, scrollEnabled: false, overScrollMode: "never", scalesPageToFit: false, showsHorizontalScrollIndicator: false, dataDetectorTypes: "none", allowsLinkPreview: false, allowsInlineMediaPlayback: true, mediaPlaybackRequiresUserAction: false, cacheEnabled: true, javaScriptEnabled: true, domStorageEnabled: true, onLoadEnd: () => {
489
+ return ((0, jsx_runtime_1.jsxs)(react_native_1.View, { style: [
490
+ styles.root,
491
+ !visible && styles.invisible,
492
+ visible && { opacity: overlayOpacity },
493
+ ], pointerEvents: visible && !isClosing ? "auto" : "none", children: [(0, jsx_runtime_1.jsx)(react_native_pager_view_1.default, { ref: pagerRef, style: react_native_1.StyleSheet.absoluteFill, scrollEnabled: false, initialPage: 0, onPageSelected: onPageSelected, offscreenPageLimit: props.screens.length, overScrollMode: "never", children: docs.map((doc, i) => ((0, jsx_runtime_1.jsx)(react_native_1.View, { style: styles.page, renderToHardwareTextureAndroid: true, children: (0, jsx_runtime_1.jsx)(react_native_webview_1.WebView, { ref: (r) => (webviewsRef.current[i] = r), style: styles.webview, originWhitelist: ["*"], source: { html: doc }, injectedJavaScriptBeforeContentLoaded: exports.injectedHardening, injectedJavaScript: exports.injectedNoSelect, automaticallyAdjustContentInsets: false, contentInsetAdjustmentBehavior: "never", bounces: false, scrollEnabled: false, overScrollMode: "never", scalesPageToFit: false, showsHorizontalScrollIndicator: false, dataDetectorTypes: "none", allowsLinkPreview: false, allowsInlineMediaPlayback: true, mediaPlaybackRequiresUserAction: false, cacheEnabled: true, javaScriptEnabled: true, domStorageEnabled: true, onLoadEnd: () => {
455
494
  setLoadedCount((c) => c + 1);
456
495
  if (i === 0)
457
496
  setFirstPageLoaded(true);
@@ -460,7 +499,7 @@ function Overlay(props) {
460
499
  console.log("[Rampkit] onLoadEnd init send vars", i);
461
500
  sendVarsToWebView(i);
462
501
  }, onMessage: (ev) => {
463
- var _a, _b;
502
+ var _a, _b, _c, _d;
464
503
  const raw = ev.nativeEvent.data;
465
504
  console.log("raw", raw);
466
505
  // Accept either raw strings or JSON payloads from your editor
@@ -543,7 +582,15 @@ function Overlay(props) {
543
582
  (_a = props.onOnboardingFinished) === null || _a === void 0 ? void 0 : _a.call(props, data === null || data === void 0 ? void 0 : data.payload);
544
583
  }
545
584
  catch (_) { }
546
- props.onRequestClose();
585
+ handleRequestClose();
586
+ return;
587
+ }
588
+ // 6) Request to show paywall
589
+ if ((data === null || data === void 0 ? void 0 : data.type) === "rampkit:show-paywall") {
590
+ try {
591
+ (_b = props.onShowPaywall) === null || _b === void 0 ? void 0 : _b.call(props);
592
+ }
593
+ catch (_) { }
547
594
  return;
548
595
  }
549
596
  if ((data === null || data === void 0 ? void 0 : data.type) === "rampkit:continue" ||
@@ -558,7 +605,7 @@ function Overlay(props) {
558
605
  navigateToIndex(i - 1);
559
606
  }
560
607
  else {
561
- props.onRequestClose();
608
+ handleRequestClose();
562
609
  }
563
610
  return;
564
611
  }
@@ -580,12 +627,12 @@ function Overlay(props) {
580
627
  navigateToIndex(i - 1);
581
628
  }
582
629
  else {
583
- props.onRequestClose();
630
+ handleRequestClose();
584
631
  }
585
632
  return;
586
633
  }
587
634
  if ((data === null || data === void 0 ? void 0 : data.type) === "rampkit:close") {
588
- props.onRequestClose();
635
+ handleRequestClose();
589
636
  return;
590
637
  }
591
638
  if ((data === null || data === void 0 ? void 0 : data.type) === "rampkit:haptic") {
@@ -593,7 +640,7 @@ function Overlay(props) {
593
640
  return;
594
641
  }
595
642
  }
596
- catch (_c) {
643
+ catch (_e) {
597
644
  // String path
598
645
  if (raw === "rampkit:tap" ||
599
646
  raw === "next" ||
@@ -627,10 +674,17 @@ function Overlay(props) {
627
674
  }
628
675
  if (raw === "rampkit:onboarding-finished") {
629
676
  try {
630
- (_b = props.onOnboardingFinished) === null || _b === void 0 ? void 0 : _b.call(props, undefined);
677
+ (_c = props.onOnboardingFinished) === null || _c === void 0 ? void 0 : _c.call(props, undefined);
678
+ }
679
+ catch (_) { }
680
+ handleRequestClose();
681
+ return;
682
+ }
683
+ if (raw === "rampkit:show-paywall") {
684
+ try {
685
+ (_d = props.onShowPaywall) === null || _d === void 0 ? void 0 : _d.call(props);
631
686
  }
632
687
  catch (_) { }
633
- props.onRequestClose();
634
688
  return;
635
689
  }
636
690
  if (raw === "rampkit:goBack") {
@@ -638,7 +692,7 @@ function Overlay(props) {
638
692
  navigateToIndex(i - 1);
639
693
  }
640
694
  else {
641
- props.onRequestClose();
695
+ handleRequestClose();
642
696
  }
643
697
  return;
644
698
  }
@@ -649,7 +703,7 @@ function Overlay(props) {
649
703
  navigateToIndex(i - 1);
650
704
  }
651
705
  else {
652
- props.onRequestClose();
706
+ handleRequestClose();
653
707
  }
654
708
  return;
655
709
  }
@@ -667,7 +721,7 @@ function Overlay(props) {
667
721
  return;
668
722
  }
669
723
  if (raw === "rampkit:close") {
670
- props.onRequestClose();
724
+ handleRequestClose();
671
725
  return;
672
726
  }
673
727
  if (raw.startsWith("haptic:")) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "rampkit-expo-dev",
3
- "version": "0.0.5",
3
+ "version": "0.0.7",
4
4
  "description": "The Expo SDK for RampKit. Build, test, and personalize app onboardings with instant updates.",
5
5
  "main": "build/index.js",
6
6
  "types": "build/index.d.ts",