@getrheo/react-native-bare 1.0.0

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 ADDED
@@ -0,0 +1,26 @@
1
+ # @getrheo/react-native-bare
2
+
3
+ Bare React Native entry for the Rheo SDK. Re-exports `@getrheo/react-native-core` and registers **bare** adapters (`react-native-video`, `react-native-in-app-review`). Do not install alongside `@getrheo/react-native-expo`.
4
+
5
+ ## Install
6
+
7
+ ```bash
8
+ pnpm add @getrheo/react-native-bare \
9
+ react react-native \
10
+ react-native-permissions react-native-gesture-handler react-native-reanimated \
11
+ react-native-linear-gradient react-native-svg lottie-react-native \
12
+ react-native-vector-icons @react-native-async-storage/async-storage \
13
+ react-native-safe-area-context react-native-in-app-review react-native-video
14
+ ```
15
+
16
+ Complete native setup for permissions (Info.plist / AndroidManifest) per [react-native-permissions](https://github.com/zoontek/react-native-permissions).
17
+
18
+ **Integrations (not SDK peers):** `react-native-appsflyer`, `react-native-purchases`, `react-native-purchases-ui` — install only when used.
19
+
20
+ ## Usage
21
+
22
+ Same API as the Expo flavor (`Flow`, `RheoProvider`, `useFlow`, …). See [`react-native-expo/README.md`](../react-native-expo/README.md) for flow semantics, events, terminal payloads, and production **`apiBaseUrl`** guidance — import from `@getrheo/react-native-bare` instead.
23
+
24
+ ## Example
25
+
26
+ [`apps/example-bare`](../../../apps/example-bare) — scaffold `ios/` / `android/` with the RN CLI before running (see example README).
@@ -0,0 +1 @@
1
+ export * from '@getrheo/react-native-core';
package/dist/index.js ADDED
@@ -0,0 +1,197 @@
1
+ import { registerAppReviewAdapter, registerVideoAdapter } from '@getrheo/react-native-core/platform';
2
+ import InAppReview from 'react-native-in-app-review';
3
+ import { useRef, useState, useCallback, useEffect } from 'react';
4
+ import { View, Text } from 'react-native';
5
+ import Video from 'react-native-video';
6
+ import { screenBackgroundPlaybackId } from '@getrheo/contracts';
7
+ import { DEFAULT_PREVIEW_VIEWPORT_WIDTH_PX, resolveImageStyleAtWidth } from '@getrheo/flow-runtime';
8
+ import { ChromeView } from '@getrheo/react-native-core/ui/LayerRendererShared';
9
+ import { mediaAutoPlayOnMount, useMediaPlayback, useMediaPlaySignal } from '@getrheo/react-native-core/ui/mediaPlayback';
10
+ import { mediaLayerOuterLayoutPair, mediaLayerInnerFillStyle } from '@getrheo/react-native-core/ui/styles';
11
+ import { fireMediaOnComplete } from '@getrheo/react-native-core/ui/layers/mediaLayers';
12
+ import { jsx } from 'react/jsx-runtime';
13
+ export * from '@getrheo/react-native-core';
14
+
15
+ // src/registerBareAdapters.ts
16
+ var APP_REVIEW_POST_PROMPT_DELAY_MS = 1500;
17
+ var delay = (ms) => new Promise((resolve) => {
18
+ setTimeout(resolve, ms);
19
+ });
20
+ var bareAppReviewAdapter = {
21
+ requestReview: async (sessionPlatform) => {
22
+ if (sessionPlatform === "web") {
23
+ return { shown: false };
24
+ }
25
+ if (!InAppReview.isAvailable()) {
26
+ return { shown: false };
27
+ }
28
+ try {
29
+ const shown = await InAppReview.RequestInAppReview();
30
+ if (!shown) {
31
+ return { shown: false };
32
+ }
33
+ await delay(APP_REVIEW_POST_PROMPT_DELAY_MS);
34
+ return { shown: true };
35
+ } catch {
36
+ return { shown: false };
37
+ }
38
+ }
39
+ };
40
+ var backdropLayout = {
41
+ position: "absolute",
42
+ top: 0,
43
+ left: 0,
44
+ right: 0,
45
+ bottom: 0,
46
+ zIndex: 0
47
+ };
48
+ var resizeModeFor = (fit) => {
49
+ if (fit === "contain") return "contain";
50
+ if (fit === "fill") return "stretch";
51
+ return "cover";
52
+ };
53
+ var useBareVideoPlayback = ({
54
+ url,
55
+ layerId,
56
+ shouldAutoplay,
57
+ loopPlay,
58
+ muted,
59
+ onPlayToEnd
60
+ }) => {
61
+ const videoRef = useRef(null);
62
+ const playback = useMediaPlayback();
63
+ const playSignal = useMediaPlaySignal(layerId);
64
+ const completedRef = useRef(false);
65
+ const [paused, setPaused] = useState(!shouldAutoplay || !url);
66
+ const play = useCallback(() => {
67
+ completedRef.current = false;
68
+ setPaused(false);
69
+ videoRef.current?.seek(0);
70
+ }, []);
71
+ useEffect(() => {
72
+ if (!playback) return;
73
+ return playback.register(layerId, { play });
74
+ }, [playback, layerId, play]);
75
+ useEffect(() => {
76
+ setPaused(!shouldAutoplay || !url);
77
+ }, [shouldAutoplay, url]);
78
+ useEffect(() => {
79
+ if (shouldAutoplay || playSignal === 0 || !url) return;
80
+ play();
81
+ }, [playSignal, shouldAutoplay, play, url]);
82
+ const onEnd = useCallback(() => {
83
+ if (loopPlay || completedRef.current) return;
84
+ completedRef.current = true;
85
+ onPlayToEnd?.();
86
+ }, [loopPlay, onPlayToEnd]);
87
+ const onError = useCallback((_e) => {
88
+ setPaused(true);
89
+ }, []);
90
+ return {
91
+ videoRef,
92
+ paused,
93
+ play,
94
+ onEnd,
95
+ onError,
96
+ loopPlay,
97
+ muted
98
+ };
99
+ };
100
+ var BareVideoLayerView = ({ layer, ctx }) => {
101
+ const w = ctx.previewWidthPx ?? DEFAULT_PREVIEW_VIEWPORT_WIDTH_PX;
102
+ const resolvedStyle = resolveImageStyleAtWidth(layer.style, layer.styleBreakpoints, w);
103
+ const url = layer.media ? ctx.mediaMap?.[layer.media.mediaAssetId] : void 0;
104
+ const shouldAutoplay = mediaAutoPlayOnMount(layer);
105
+ const loopPlay = layer.loop !== false;
106
+ const muted = layer.audioEnabled !== true;
107
+ const { videoRef, paused, onEnd, onError, loopPlay: loop, muted: isMuted } = useBareVideoPlayback({
108
+ url,
109
+ layerId: layer.id,
110
+ shouldAutoplay,
111
+ loopPlay,
112
+ muted,
113
+ onPlayToEnd: () => fireMediaOnComplete(ctx, layer)
114
+ });
115
+ const { outerStyle, linearGradient } = mediaLayerOuterLayoutPair(
116
+ resolvedStyle,
117
+ ctx.manifest.theme,
118
+ ctx.theme,
119
+ ctx.branding
120
+ );
121
+ const placeholderBg = ctx.theme === "dark" ? "#18181b" : "#f4f4f5";
122
+ const hasAuthorBg = linearGradient != null || outerStyle.backgroundColor !== void 0;
123
+ const innerStyle = {
124
+ ...mediaLayerInnerFillStyle(resolvedStyle),
125
+ borderRadius: outerStyle.borderRadius ?? 10,
126
+ ...!hasAuthorBg && !url ? { backgroundColor: placeholderBg } : {}
127
+ };
128
+ const r = innerStyle.borderRadius;
129
+ const resizeMode = resizeModeFor(resolvedStyle?.fit ?? "contain");
130
+ return /* @__PURE__ */ jsx(ChromeView, { style: outerStyle, linearGradient, children: url ? /* @__PURE__ */ jsx(View, { style: innerStyle, children: /* @__PURE__ */ jsx(
131
+ Video,
132
+ {
133
+ ref: videoRef,
134
+ source: { uri: url },
135
+ style: {
136
+ width: "100%",
137
+ height: "100%",
138
+ ...r !== void 0 ? { borderRadius: r } : {}
139
+ },
140
+ resizeMode,
141
+ repeat: loop,
142
+ muted: isMuted,
143
+ paused,
144
+ onEnd,
145
+ onError
146
+ }
147
+ ) }) : /* @__PURE__ */ jsx(View, { style: [innerStyle, { alignItems: "center", justifyContent: "center" }], children: /* @__PURE__ */ jsx(Text, { style: { color: "#71717a", fontSize: 11 }, children: "No media" }) }) });
148
+ };
149
+ var BareScreenShellVideoBackdrop = ({
150
+ screenId,
151
+ url,
152
+ fill,
153
+ ctx
154
+ }) => {
155
+ const shouldAutoplay = mediaAutoPlayOnMount(fill);
156
+ const loopPlay = fill.loop !== false;
157
+ const muted = fill.audioEnabled !== true;
158
+ const playbackId = screenBackgroundPlaybackId(screenId);
159
+ const { videoRef, paused, onEnd, onError, loopPlay: loop, muted: isMuted } = useBareVideoPlayback({
160
+ url,
161
+ layerId: playbackId,
162
+ shouldAutoplay,
163
+ loopPlay,
164
+ muted,
165
+ onPlayToEnd: () => {
166
+ const mode = fill.onComplete?.mode ?? "none";
167
+ if (mode === "next") ctx.onRespond?.({ kind: "cta", action: "primary" });
168
+ }
169
+ });
170
+ return /* @__PURE__ */ jsx(View, { style: backdropLayout, pointerEvents: "none", collapsable: false, children: /* @__PURE__ */ jsx(
171
+ Video,
172
+ {
173
+ ref: videoRef,
174
+ source: { uri: url },
175
+ style: {
176
+ width: "100%",
177
+ height: "100%",
178
+ opacity: fill.opacity ?? 1
179
+ },
180
+ resizeMode: resizeModeFor(fill.fit),
181
+ repeat: loop,
182
+ muted: isMuted,
183
+ paused,
184
+ onEnd,
185
+ onError
186
+ }
187
+ ) });
188
+ };
189
+
190
+ // src/registerBareAdapters.ts
191
+ registerAppReviewAdapter(bareAppReviewAdapter);
192
+ registerVideoAdapter({
193
+ VideoLayerView: BareVideoLayerView,
194
+ ScreenShellVideoBackdrop: BareScreenShellVideoBackdrop
195
+ });
196
+ //# sourceMappingURL=index.js.map
197
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/adapters/bareAppReview.ts","../src/adapters/bareVideo.tsx","../src/registerBareAdapters.ts"],"names":[],"mappings":"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","file":"index.js","sourcesContent":["import InAppReview from 'react-native-in-app-review';\nimport type { AppReviewAdapter } from '@getrheo/react-native-core/platform';\nimport type { AppReviewRequestResult } from '@getrheo/react-native-core';\n\nconst APP_REVIEW_POST_PROMPT_DELAY_MS = 1500;\n\nconst delay = (ms: number): Promise<void> =>\n new Promise((resolve) => {\n setTimeout(resolve, ms);\n });\n\nexport const bareAppReviewAdapter: AppReviewAdapter = {\n requestReview: async (sessionPlatform: string): Promise<AppReviewRequestResult> => {\n if (sessionPlatform === 'web') {\n return { shown: false };\n }\n\n if (!InAppReview.isAvailable()) {\n return { shown: false };\n }\n\n try {\n const shown = await InAppReview.RequestInAppReview();\n if (!shown) {\n return { shown: false };\n }\n await delay(APP_REVIEW_POST_PROMPT_DELAY_MS);\n return { shown: true };\n } catch {\n return { shown: false };\n }\n },\n};\n","import { useCallback, useEffect, useRef, useState } from 'react';\nimport { Text, View } from 'react-native';\nimport type { ViewStyle } from 'react-native';\nimport Video, { type OnVideoErrorData, type VideoRef } from 'react-native-video';\nimport { screenBackgroundPlaybackId } from '@getrheo/contracts';\nimport { DEFAULT_PREVIEW_VIEWPORT_WIDTH_PX, resolveImageStyleAtWidth } from '@getrheo/flow-runtime';\nimport { ChromeView } from '@getrheo/react-native-core/ui/LayerRendererShared';\nimport {\n mediaAutoPlayOnMount,\n useMediaPlayback,\n useMediaPlaySignal,\n} from '@getrheo/react-native-core/ui/mediaPlayback';\nimport {\n mediaLayerInnerFillStyle,\n mediaLayerOuterLayoutPair,\n} from '@getrheo/react-native-core/ui/styles';\nimport { fireMediaOnComplete } from '@getrheo/react-native-core/ui/layers/mediaLayers';\nimport type {\n ScreenShellVideoBackdropProps,\n VideoLayerViewProps,\n} from '@getrheo/react-native-core/platform';\n\nconst backdropLayout: ViewStyle = {\n position: 'absolute',\n top: 0,\n left: 0,\n right: 0,\n bottom: 0,\n zIndex: 0,\n};\n\nconst resizeModeFor = (\n fit: 'cover' | 'contain' | 'fill' | undefined,\n): 'cover' | 'contain' | 'stretch' => {\n if (fit === 'contain') return 'contain';\n if (fit === 'fill') return 'stretch';\n return 'cover';\n};\n\nconst useBareVideoPlayback = ({\n url,\n layerId,\n shouldAutoplay,\n loopPlay,\n muted,\n onPlayToEnd,\n}: {\n url: string | undefined;\n layerId: string;\n shouldAutoplay: boolean;\n loopPlay: boolean;\n muted: boolean;\n onPlayToEnd?: () => void;\n}) => {\n const videoRef = useRef<VideoRef>(null);\n const playback = useMediaPlayback();\n const playSignal = useMediaPlaySignal(layerId);\n const completedRef = useRef(false);\n const [paused, setPaused] = useState(!shouldAutoplay || !url);\n\n const play = useCallback(() => {\n completedRef.current = false;\n setPaused(false);\n videoRef.current?.seek(0);\n }, []);\n\n useEffect(() => {\n if (!playback) return;\n return playback.register(layerId, { play });\n }, [playback, layerId, play]);\n\n useEffect(() => {\n setPaused(!shouldAutoplay || !url);\n }, [shouldAutoplay, url]);\n\n useEffect(() => {\n if (shouldAutoplay || playSignal === 0 || !url) return;\n play();\n }, [playSignal, shouldAutoplay, play, url]);\n\n const onEnd = useCallback(() => {\n if (loopPlay || completedRef.current) return;\n completedRef.current = true;\n onPlayToEnd?.();\n }, [loopPlay, onPlayToEnd]);\n\n const onError = useCallback((_e: OnVideoErrorData) => {\n setPaused(true);\n }, []);\n\n return {\n videoRef,\n paused,\n play,\n onEnd,\n onError,\n loopPlay,\n muted,\n };\n};\n\nexport const BareVideoLayerView = ({ layer, ctx }: VideoLayerViewProps) => {\n const w = ctx.previewWidthPx ?? DEFAULT_PREVIEW_VIEWPORT_WIDTH_PX;\n const resolvedStyle = resolveImageStyleAtWidth(layer.style, layer.styleBreakpoints, w);\n const url = layer.media ? ctx.mediaMap?.[layer.media.mediaAssetId] : undefined;\n const shouldAutoplay = mediaAutoPlayOnMount(layer);\n const loopPlay = layer.loop !== false;\n const muted = layer.audioEnabled !== true;\n\n const { videoRef, paused, onEnd, onError, loopPlay: loop, muted: isMuted } =\n useBareVideoPlayback({\n url,\n layerId: layer.id,\n shouldAutoplay,\n loopPlay,\n muted,\n onPlayToEnd: () => fireMediaOnComplete(ctx, layer),\n });\n\n const { outerStyle, linearGradient } = mediaLayerOuterLayoutPair(\n resolvedStyle,\n ctx.manifest.theme,\n ctx.theme,\n ctx.branding,\n );\n const placeholderBg = ctx.theme === 'dark' ? '#18181b' : '#f4f4f5';\n const hasAuthorBg =\n linearGradient != null || outerStyle.backgroundColor !== undefined;\n const innerStyle = {\n ...mediaLayerInnerFillStyle(resolvedStyle),\n borderRadius: outerStyle.borderRadius ?? 10,\n ...(!hasAuthorBg && !url ? { backgroundColor: placeholderBg } : {}),\n };\n const r = innerStyle.borderRadius as number | undefined;\n const resizeMode = resizeModeFor(resolvedStyle?.fit ?? 'contain');\n\n return (\n <ChromeView style={outerStyle} linearGradient={linearGradient}>\n {url ? (\n <View style={innerStyle}>\n <Video\n ref={videoRef}\n source={{ uri: url }}\n style={{\n width: '100%',\n height: '100%',\n ...(r !== undefined ? { borderRadius: r } : {}),\n }}\n resizeMode={resizeMode}\n repeat={loop}\n muted={isMuted}\n paused={paused}\n onEnd={onEnd}\n onError={onError}\n />\n </View>\n ) : (\n <View style={[innerStyle, { alignItems: 'center', justifyContent: 'center' }]}>\n <Text style={{ color: '#71717a', fontSize: 11 }}>No media</Text>\n </View>\n )}\n </ChromeView>\n );\n};\n\nexport const BareScreenShellVideoBackdrop = ({\n screenId,\n url,\n fill,\n ctx,\n}: ScreenShellVideoBackdropProps) => {\n const shouldAutoplay = mediaAutoPlayOnMount(fill);\n const loopPlay = fill.loop !== false;\n const muted = fill.audioEnabled !== true;\n const playbackId = screenBackgroundPlaybackId(screenId);\n\n const { videoRef, paused, onEnd, onError, loopPlay: loop, muted: isMuted } =\n useBareVideoPlayback({\n url,\n layerId: playbackId,\n shouldAutoplay,\n loopPlay,\n muted,\n onPlayToEnd: () => {\n const mode = fill.onComplete?.mode ?? 'none';\n if (mode === 'next') ctx.onRespond?.({ kind: 'cta', action: 'primary' });\n },\n });\n\n return (\n <View style={backdropLayout} pointerEvents=\"none\" collapsable={false}>\n <Video\n ref={videoRef}\n source={{ uri: url }}\n style={{\n width: '100%',\n height: '100%',\n opacity: fill.opacity ?? 1,\n }}\n resizeMode={resizeModeFor(fill.fit)}\n repeat={loop}\n muted={isMuted}\n paused={paused}\n onEnd={onEnd}\n onError={onError}\n />\n </View>\n );\n};\n","import { registerAppReviewAdapter, registerVideoAdapter } from '@getrheo/react-native-core/platform';\nimport { bareAppReviewAdapter } from './adapters/bareAppReview.js';\nimport { BareScreenShellVideoBackdrop, BareVideoLayerView } from './adapters/bareVideo.js';\n\nregisterAppReviewAdapter(bareAppReviewAdapter);\nregisterVideoAdapter({\n VideoLayerView: BareVideoLayerView,\n ScreenShellVideoBackdrop: BareScreenShellVideoBackdrop,\n});\n"]}
@@ -0,0 +1,6 @@
1
+ [
2
+ {
3
+ "exportKey": ".",
4
+ "distFile": "./dist/index.js"
5
+ }
6
+ ]
package/package.json ADDED
@@ -0,0 +1,73 @@
1
+ {
2
+ "name": "@getrheo/react-native-bare",
3
+ "version": "1.0.0",
4
+ "type": "module",
5
+ "main": "./dist/index.js",
6
+ "types": "./dist/index.d.ts",
7
+ "exports": {
8
+ ".": {
9
+ "types": "./dist/index.d.ts",
10
+ "import": "./dist/index.js",
11
+ "default": "./dist/index.js"
12
+ }
13
+ },
14
+ "dependencies": {
15
+ "@getrheo/react-native-core": "1.0.0"
16
+ },
17
+ "peerDependencies": {
18
+ "@react-native-async-storage/async-storage": ">=2",
19
+ "lottie-react-native": "*",
20
+ "react": ">=18",
21
+ "react-native": ">=0.79",
22
+ "react-native-gesture-handler": "*",
23
+ "react-native-in-app-review": "*",
24
+ "react-native-linear-gradient": "*",
25
+ "react-native-permissions": ">=5",
26
+ "react-native-reanimated": "*",
27
+ "react-native-safe-area-context": "*",
28
+ "react-native-svg": "*",
29
+ "react-native-vector-icons": ">=10",
30
+ "react-native-video": "*"
31
+ },
32
+ "devDependencies": {
33
+ "@react-native-async-storage/async-storage": "2.2.0",
34
+ "@types/react": "^19.0.1",
35
+ "lottie-react-native": "^7.2.2",
36
+ "react": "^19.0.0",
37
+ "react-native": "0.83.6",
38
+ "react-native-gesture-handler": "~2.30.1",
39
+ "react-native-in-app-review": "^4.3.3",
40
+ "react-native-linear-gradient": "^2.8.3",
41
+ "react-native-permissions": "^5.5.1",
42
+ "react-native-reanimated": "~4.2.1",
43
+ "react-native-safe-area-context": "~5.6.1",
44
+ "react-native-svg": "15.15.4",
45
+ "react-native-vector-icons": "^10.2.0",
46
+ "react-native-video": "^6.10.2",
47
+ "typescript": "^5.6.3",
48
+ "vitest": "^3.2.6",
49
+ "@getrheo/contracts": "1.0.0",
50
+ "@getrheo/flow-runtime": "1.0.0",
51
+ "@getrheo/react-native-core": "1.0.0",
52
+ "@rheo/config": "0.1.0"
53
+ },
54
+ "license": "MIT",
55
+ "repository": {
56
+ "type": "git",
57
+ "url": "git+https://github.com/madeinusmate/onboardly.git",
58
+ "directory": "packages/sdks/react-native-bare"
59
+ },
60
+ "files": [
61
+ "dist",
62
+ "README.md"
63
+ ],
64
+ "publishConfig": {
65
+ "access": "public"
66
+ },
67
+ "scripts": {
68
+ "lint": "eslint .",
69
+ "typecheck": "tsc --noEmit",
70
+ "test": "vitest run --passWithNoTests --config ../react-native-core/vitest.config.ts",
71
+ "build": "node ../../../scripts/build-publishable-package.mjs"
72
+ }
73
+ }