@vitraun/react-native 0.1.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/LICENSE.txt +10 -0
- package/README.md +90 -0
- package/dist/index.d.ts +116 -0
- package/dist/index.js +418 -0
- package/package.json +48 -0
package/LICENSE.txt
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
Vitraun — software license
|
|
2
|
+
|
|
3
|
+
Copyright (c) Vitraun. All rights reserved.
|
|
4
|
+
|
|
5
|
+
This package is proprietary. Redistribution, modification, sublicensing,
|
|
6
|
+
or use beyond the rights expressly granted in your written agreement with
|
|
7
|
+
Vitraun is prohibited unless Vitraun authorizes otherwise in writing.
|
|
8
|
+
|
|
9
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND. For
|
|
10
|
+
licensing inquiries, contact Vitraun.
|
package/README.md
ADDED
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
# @vitraun/react-native
|
|
2
|
+
|
|
3
|
+
Official Vitraun Try-On adapter for React Native apps. The SDK calls **embed-init**, loads the returned **`vtoUrl`** in a WebView, and forwards cart events to your app.
|
|
4
|
+
|
|
5
|
+
The integrator **does not** hardcode the try-on URL.
|
|
6
|
+
|
|
7
|
+
## Install
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
npm install @vitraun/react-native react-native-webview
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
Peer dependencies: `react`, `react-native`, `react-native-webview`.
|
|
14
|
+
|
|
15
|
+
## Prerequisites (Vitraun panel)
|
|
16
|
+
|
|
17
|
+
- Register **merchant ID** and **widget ID**
|
|
18
|
+
- Enable **`allowWebView`** on the channel
|
|
19
|
+
- Register **iOS bundle ID** and/or **Android package name**
|
|
20
|
+
- Add camera permission:
|
|
21
|
+
- iOS: `NSCameraUsageDescription` in `Info.plist`
|
|
22
|
+
- Android: `CAMERA` in `AndroidManifest.xml`
|
|
23
|
+
|
|
24
|
+
## Usage
|
|
25
|
+
|
|
26
|
+
```tsx
|
|
27
|
+
import { VitraunTryOn } from '@vitraun/react-native'
|
|
28
|
+
|
|
29
|
+
export const TryOnScreen = () => (
|
|
30
|
+
<VitraunTryOn
|
|
31
|
+
merchantId="vtrn-mch-key-00000000-0000-4000-8000-000000000001"
|
|
32
|
+
widgetId="vtrn-wdg-key-00000000-0000-4000-8000-000000000002"
|
|
33
|
+
lang="pt-BR"
|
|
34
|
+
platform="ios"
|
|
35
|
+
bundleId="com.sua.loja"
|
|
36
|
+
packageName="com.sua.loja"
|
|
37
|
+
isolatedSku="8028997081552"
|
|
38
|
+
basketOpensIn="event"
|
|
39
|
+
checkoutOpensIn="event"
|
|
40
|
+
onEvent={(event) => {
|
|
41
|
+
switch (event.type) {
|
|
42
|
+
case 'addToCart':
|
|
43
|
+
break
|
|
44
|
+
case 'redirectToCart':
|
|
45
|
+
break
|
|
46
|
+
default:
|
|
47
|
+
break
|
|
48
|
+
}
|
|
49
|
+
}}
|
|
50
|
+
/>
|
|
51
|
+
)
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
## Init without UI
|
|
55
|
+
|
|
56
|
+
```ts
|
|
57
|
+
import { initializeVitraunSession } from '@vitraun/react-native'
|
|
58
|
+
|
|
59
|
+
const session = await initializeVitraunSession({
|
|
60
|
+
state: {
|
|
61
|
+
merchantId: 'vtrn-mch-key-...',
|
|
62
|
+
widgetId: 'vtrn-wdg-key-...',
|
|
63
|
+
lang: 'en-US',
|
|
64
|
+
app: { platform: 'android', packageName: 'com.sua.loja' },
|
|
65
|
+
},
|
|
66
|
+
})
|
|
67
|
+
|
|
68
|
+
// session.vtoUrl — load in your own WebView if needed
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
## Staging
|
|
72
|
+
|
|
73
|
+
```tsx
|
|
74
|
+
<VitraunTryOn env="staging" merchantId="..." widgetId="..." />
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
## Events
|
|
78
|
+
|
|
79
|
+
Same contract as `@vitraun/webar`:
|
|
80
|
+
|
|
81
|
+
- `addToCart`
|
|
82
|
+
- `removeFromCart`
|
|
83
|
+
- `redirectToCart`
|
|
84
|
+
- `analysisFinished`
|
|
85
|
+
|
|
86
|
+
## Related docs
|
|
87
|
+
|
|
88
|
+
- Mobile HTTP contract: [`../docs/mobile-sdk-contract.md`](../docs/mobile-sdk-contract.md)
|
|
89
|
+
- iOS native stub: [`../ios/README.md`](../ios/README.md)
|
|
90
|
+
- Android native stub: [`../android/README.md`](../android/README.md)
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
import type { StyleProp, ViewStyle } from 'react-native'
|
|
2
|
+
import type {
|
|
3
|
+
PostEmbedInitOptions,
|
|
4
|
+
VitraunEmbedInitSession,
|
|
5
|
+
VitraunEmbedInitState,
|
|
6
|
+
VitraunVTOEventType,
|
|
7
|
+
} from '@vitraun/core'
|
|
8
|
+
|
|
9
|
+
export type {
|
|
10
|
+
PostEmbedInitOptions,
|
|
11
|
+
VitraunEmbedInitSession,
|
|
12
|
+
VitraunEmbedInitState,
|
|
13
|
+
VitraunVTOEventType,
|
|
14
|
+
} from '@vitraun/core'
|
|
15
|
+
|
|
16
|
+
export {
|
|
17
|
+
VITRAUN_VTO_DEFAULT_EVENT_TYPES,
|
|
18
|
+
VITRAUN_VTO_EXTRA_EVENT_TYPES,
|
|
19
|
+
initializeVitraunSession,
|
|
20
|
+
postEmbedInit,
|
|
21
|
+
} from '@vitraun/core'
|
|
22
|
+
|
|
23
|
+
export type VitraunBridgeEvent = {
|
|
24
|
+
type: VitraunVTOEventType
|
|
25
|
+
detail?: unknown
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export type VitraunTryOnBasketOpensIn = 'blank' | 'self' | 'event'
|
|
29
|
+
export type VitraunTryOnCheckoutOpensIn = 'blank' | 'self' | 'event'
|
|
30
|
+
export type VitraunTryOnFlow = 'checkout' | 'catalog'
|
|
31
|
+
|
|
32
|
+
export type VitraunTryOnProps = {
|
|
33
|
+
merchantId: string
|
|
34
|
+
widgetId: string
|
|
35
|
+
lang?: string
|
|
36
|
+
env?: string
|
|
37
|
+
apiPort?: number | null
|
|
38
|
+
appPort?: number | null
|
|
39
|
+
isolatedSku?: string
|
|
40
|
+
applySkus?: string[]
|
|
41
|
+
flow?: VitraunTryOnFlow
|
|
42
|
+
basketOpensIn?: VitraunTryOnBasketOpensIn
|
|
43
|
+
checkoutOpensIn?: VitraunTryOnCheckoutOpensIn
|
|
44
|
+
useSimplePage?: boolean
|
|
45
|
+
showDetails?: boolean
|
|
46
|
+
showProductPrice?: boolean
|
|
47
|
+
priceFrom?: number | null
|
|
48
|
+
priceTo?: number | null
|
|
49
|
+
currencySymbol?: string | null
|
|
50
|
+
isSimulationMode?: boolean
|
|
51
|
+
platform?: string
|
|
52
|
+
bundleId?: string
|
|
53
|
+
packageName?: string
|
|
54
|
+
appId?: string
|
|
55
|
+
appVersion?: string
|
|
56
|
+
attestationToken?: string
|
|
57
|
+
embedParentOrigin?: string | null
|
|
58
|
+
pageUrl?: string | null
|
|
59
|
+
referrer?: string | null
|
|
60
|
+
userAgent?: string | null
|
|
61
|
+
timezone?: string | null
|
|
62
|
+
initTimeoutMs?: number
|
|
63
|
+
autoInit?: boolean
|
|
64
|
+
onEvent?: (event: VitraunBridgeEvent) => void
|
|
65
|
+
onError?: (error: Error) => void
|
|
66
|
+
onReady?: () => void
|
|
67
|
+
style?: StyleProp<ViewStyle>
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
export type UseVitraunInitOptions = {
|
|
71
|
+
enabled?: boolean
|
|
72
|
+
state: VitraunEmbedInitState
|
|
73
|
+
sessionStorage?: PostEmbedInitOptions['sessionStorage']
|
|
74
|
+
sessionInstanceId?: string
|
|
75
|
+
timeoutMs?: number
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
export type UseVitraunInitResult = {
|
|
79
|
+
status: 'idle' | 'loading' | 'ready' | 'error'
|
|
80
|
+
session: VitraunEmbedInitSession | null
|
|
81
|
+
error: Error | null
|
|
82
|
+
reload: () => Promise<VitraunEmbedInitSession | null>
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
export const handleVitraunWebViewMessage: (
|
|
86
|
+
raw: string,
|
|
87
|
+
onEvent?: (event: VitraunBridgeEvent) => void,
|
|
88
|
+
) => void
|
|
89
|
+
|
|
90
|
+
export const parseVitraunBridgeMessage: (
|
|
91
|
+
raw: string,
|
|
92
|
+
) => VitraunBridgeEvent | null
|
|
93
|
+
|
|
94
|
+
export const buildInjectedBridgeScript: () => string
|
|
95
|
+
export const buildNativeConfigInjectScript: (
|
|
96
|
+
overrides: Record<string, unknown> | null | undefined,
|
|
97
|
+
) => string
|
|
98
|
+
export const buildInjectedJavaScriptBeforeContentLoaded: (
|
|
99
|
+
nativeOverrides: Record<string, unknown> | null | undefined,
|
|
100
|
+
) => string
|
|
101
|
+
|
|
102
|
+
export const buildEmbedInitStateFromProps: (
|
|
103
|
+
props: VitraunTryOnProps,
|
|
104
|
+
) => VitraunEmbedInitState
|
|
105
|
+
|
|
106
|
+
export const buildNativeConfigOverrides: (
|
|
107
|
+
props: VitraunTryOnProps,
|
|
108
|
+
) => Record<string, unknown> | null
|
|
109
|
+
|
|
110
|
+
export const useVitraunInit: (
|
|
111
|
+
options: UseVitraunInitOptions,
|
|
112
|
+
) => UseVitraunInitResult
|
|
113
|
+
|
|
114
|
+
export const VitraunTryOn: (
|
|
115
|
+
props: VitraunTryOnProps,
|
|
116
|
+
) => JSX.Element
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,418 @@
|
|
|
1
|
+
// src/index.js
|
|
2
|
+
import {
|
|
3
|
+
VITRAUN_VTO_DEFAULT_EVENT_TYPES as VITRAUN_VTO_DEFAULT_EVENT_TYPES2,
|
|
4
|
+
VITRAUN_VTO_EXTRA_EVENT_TYPES,
|
|
5
|
+
initializeVitraunSession,
|
|
6
|
+
postEmbedInit as postEmbedInit2
|
|
7
|
+
} from "@vitraun/core";
|
|
8
|
+
|
|
9
|
+
// src/bridge.js
|
|
10
|
+
import { VITRAUN_VTO_DEFAULT_EVENT_TYPES } from "@vitraun/core";
|
|
11
|
+
var DEFAULT_EVENT_TYPES = new Set(VITRAUN_VTO_DEFAULT_EVENT_TYPES);
|
|
12
|
+
var parseVitraunBridgeMessage = (raw) => {
|
|
13
|
+
if (typeof raw !== "string" || !raw.trim()) {
|
|
14
|
+
return null;
|
|
15
|
+
}
|
|
16
|
+
try {
|
|
17
|
+
const data = JSON.parse(raw);
|
|
18
|
+
if (!data || typeof data !== "object") {
|
|
19
|
+
return null;
|
|
20
|
+
}
|
|
21
|
+
const type = typeof data.type === "string" ? data.type.trim() : "";
|
|
22
|
+
if (!type || !DEFAULT_EVENT_TYPES.has(type)) {
|
|
23
|
+
return null;
|
|
24
|
+
}
|
|
25
|
+
return {
|
|
26
|
+
type,
|
|
27
|
+
detail: "detail" in data ? data.detail : void 0
|
|
28
|
+
};
|
|
29
|
+
} catch {
|
|
30
|
+
return null;
|
|
31
|
+
}
|
|
32
|
+
};
|
|
33
|
+
var handleVitraunWebViewMessage = (raw, onEvent) => {
|
|
34
|
+
const event = parseVitraunBridgeMessage(raw);
|
|
35
|
+
if (!event || typeof onEvent !== "function") {
|
|
36
|
+
return;
|
|
37
|
+
}
|
|
38
|
+
onEvent(event);
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
// src/injected-bridge.js
|
|
42
|
+
var buildInjectedBridgeScript = () => `
|
|
43
|
+
(function() {
|
|
44
|
+
if (window.__vitraunRnBridgeInstalled) {
|
|
45
|
+
return true;
|
|
46
|
+
}
|
|
47
|
+
window.__vitraunRnBridgeInstalled = true;
|
|
48
|
+
window.addEventListener('message', function(event) {
|
|
49
|
+
var data = event.data;
|
|
50
|
+
if (!data || typeof data !== 'object' || !data.type) {
|
|
51
|
+
return;
|
|
52
|
+
}
|
|
53
|
+
if (window.ReactNativeWebView && typeof window.ReactNativeWebView.postMessage === 'function') {
|
|
54
|
+
window.ReactNativeWebView.postMessage(JSON.stringify(data));
|
|
55
|
+
}
|
|
56
|
+
});
|
|
57
|
+
true;
|
|
58
|
+
})();`;
|
|
59
|
+
var buildNativeConfigInjectScript = (overrides) => {
|
|
60
|
+
if (!overrides || Object.keys(overrides).length === 0) {
|
|
61
|
+
return "";
|
|
62
|
+
}
|
|
63
|
+
const serialized = JSON.stringify(overrides);
|
|
64
|
+
return `
|
|
65
|
+
(function() {
|
|
66
|
+
window.__TRYON_NATIVE_CONFIG__ = Object.assign(
|
|
67
|
+
window.__TRYON_NATIVE_CONFIG__ || {},
|
|
68
|
+
${serialized}
|
|
69
|
+
);
|
|
70
|
+
true;
|
|
71
|
+
})();`;
|
|
72
|
+
};
|
|
73
|
+
var buildInjectedJavaScriptBeforeContentLoaded = (nativeOverrides) => {
|
|
74
|
+
const parts = [
|
|
75
|
+
buildNativeConfigInjectScript(nativeOverrides),
|
|
76
|
+
buildInjectedBridgeScript()
|
|
77
|
+
].filter((part) => part.trim().length > 0);
|
|
78
|
+
return parts.join("\n");
|
|
79
|
+
};
|
|
80
|
+
|
|
81
|
+
// src/native-config-inject.js
|
|
82
|
+
var buildNativeConfigOverrides = (props) => {
|
|
83
|
+
const overrides = {};
|
|
84
|
+
if (props.basketOpensIn) {
|
|
85
|
+
overrides.basketOpensIn = props.basketOpensIn;
|
|
86
|
+
}
|
|
87
|
+
if (props.checkoutOpensIn) {
|
|
88
|
+
overrides.checkoutOpensIn = props.checkoutOpensIn;
|
|
89
|
+
}
|
|
90
|
+
if (props.flow) {
|
|
91
|
+
overrides.flow = props.flow;
|
|
92
|
+
}
|
|
93
|
+
if (props.useSimplePage != null) {
|
|
94
|
+
overrides.useSimplePage = props.useSimplePage;
|
|
95
|
+
}
|
|
96
|
+
if (props.showDetails != null) {
|
|
97
|
+
overrides.showDetails = props.showDetails;
|
|
98
|
+
}
|
|
99
|
+
if (props.showProductPrice != null) {
|
|
100
|
+
overrides.showProductPrice = props.showProductPrice;
|
|
101
|
+
}
|
|
102
|
+
if (props.priceFrom != null) {
|
|
103
|
+
overrides.priceFrom = props.priceFrom;
|
|
104
|
+
}
|
|
105
|
+
if (props.priceTo != null) {
|
|
106
|
+
overrides.priceTo = props.priceTo;
|
|
107
|
+
}
|
|
108
|
+
if (props.currencySymbol != null) {
|
|
109
|
+
overrides.currencySymbol = props.currencySymbol;
|
|
110
|
+
}
|
|
111
|
+
if (props.isolatedSku) {
|
|
112
|
+
overrides.isolatedSku = props.isolatedSku;
|
|
113
|
+
}
|
|
114
|
+
if (Array.isArray(props.applySkus) && props.applySkus.length > 0) {
|
|
115
|
+
overrides.applySkus = props.applySkus;
|
|
116
|
+
}
|
|
117
|
+
if (props.isSimulationMode != null) {
|
|
118
|
+
overrides.isSimulationMode = props.isSimulationMode;
|
|
119
|
+
}
|
|
120
|
+
return Object.keys(overrides).length > 0 ? overrides : null;
|
|
121
|
+
};
|
|
122
|
+
var buildEmbedInitStateFromProps = (props) => {
|
|
123
|
+
const platform = typeof props.platform === "string" && props.platform.trim() ? props.platform.trim() : void 0;
|
|
124
|
+
return {
|
|
125
|
+
merchantId: String(props.merchantId ?? "").trim(),
|
|
126
|
+
widgetId: String(props.widgetId ?? "").trim(),
|
|
127
|
+
env: props.env ?? "",
|
|
128
|
+
apiPort: props.apiPort ?? null,
|
|
129
|
+
appPort: props.appPort ?? null,
|
|
130
|
+
lang: props.lang ?? "en-US",
|
|
131
|
+
isSimulationMode: props.isSimulationMode === true,
|
|
132
|
+
app: {
|
|
133
|
+
appId: props.appId ?? null,
|
|
134
|
+
platform: platform ?? null,
|
|
135
|
+
bundleId: props.bundleId ?? null,
|
|
136
|
+
packageName: props.packageName ?? null,
|
|
137
|
+
appVersion: props.appVersion ?? null,
|
|
138
|
+
attestationToken: props.attestationToken ?? null
|
|
139
|
+
},
|
|
140
|
+
context: {
|
|
141
|
+
origin: props.embedParentOrigin ?? null,
|
|
142
|
+
pageUrl: props.pageUrl ?? null,
|
|
143
|
+
referrer: props.referrer ?? null,
|
|
144
|
+
userAgent: props.userAgent ?? null,
|
|
145
|
+
timezone: props.timezone ?? null
|
|
146
|
+
}
|
|
147
|
+
};
|
|
148
|
+
};
|
|
149
|
+
|
|
150
|
+
// src/use-vitraun-init.js
|
|
151
|
+
import { useCallback, useEffect, useMemo, useRef, useState } from "react";
|
|
152
|
+
import { postEmbedInit } from "@vitraun/core";
|
|
153
|
+
var useVitraunInit = (options) => {
|
|
154
|
+
const enabled = options.enabled !== false;
|
|
155
|
+
const [status, setStatus] = useState(
|
|
156
|
+
/** @type {'idle' | 'loading' | 'ready' | 'error'} */
|
|
157
|
+
"idle"
|
|
158
|
+
);
|
|
159
|
+
const [session, setSession] = useState(
|
|
160
|
+
/** @type {VitraunEmbedInitSession | null} */
|
|
161
|
+
null
|
|
162
|
+
);
|
|
163
|
+
const [error, setError] = useState(
|
|
164
|
+
/** @type {Error | null} */
|
|
165
|
+
null
|
|
166
|
+
);
|
|
167
|
+
const requestIdRef = useRef(0);
|
|
168
|
+
const initOptions = useMemo(
|
|
169
|
+
() => ({
|
|
170
|
+
state: options.state,
|
|
171
|
+
sessionStorage: options.sessionStorage,
|
|
172
|
+
sessionInstanceId: options.sessionInstanceId,
|
|
173
|
+
timeoutMs: options.timeoutMs
|
|
174
|
+
}),
|
|
175
|
+
[
|
|
176
|
+
options.state,
|
|
177
|
+
options.sessionStorage,
|
|
178
|
+
options.sessionInstanceId,
|
|
179
|
+
options.timeoutMs
|
|
180
|
+
]
|
|
181
|
+
);
|
|
182
|
+
const runInit = useCallback(async () => {
|
|
183
|
+
if (!enabled) {
|
|
184
|
+
return null;
|
|
185
|
+
}
|
|
186
|
+
const merchantId = initOptions.state.merchantId?.trim();
|
|
187
|
+
const widgetId = initOptions.state.widgetId?.trim();
|
|
188
|
+
if (!merchantId || !widgetId) {
|
|
189
|
+
const validationError = new Error(
|
|
190
|
+
!merchantId ? "The merchant-id attribute is required." : "The widget-id attribute is required."
|
|
191
|
+
);
|
|
192
|
+
setStatus("error");
|
|
193
|
+
setError(validationError);
|
|
194
|
+
setSession(null);
|
|
195
|
+
return null;
|
|
196
|
+
}
|
|
197
|
+
const requestId = requestIdRef.current + 1;
|
|
198
|
+
requestIdRef.current = requestId;
|
|
199
|
+
setStatus("loading");
|
|
200
|
+
setError(null);
|
|
201
|
+
try {
|
|
202
|
+
const result = await postEmbedInit(fetch, initOptions);
|
|
203
|
+
if (requestIdRef.current !== requestId) {
|
|
204
|
+
return null;
|
|
205
|
+
}
|
|
206
|
+
setSession(result);
|
|
207
|
+
setStatus("ready");
|
|
208
|
+
return result;
|
|
209
|
+
} catch (initError) {
|
|
210
|
+
if (requestIdRef.current !== requestId) {
|
|
211
|
+
return null;
|
|
212
|
+
}
|
|
213
|
+
const normalized = initError instanceof Error ? initError : new Error("Could not start the virtual try-on. Please try again.");
|
|
214
|
+
setSession(null);
|
|
215
|
+
setStatus("error");
|
|
216
|
+
setError(normalized);
|
|
217
|
+
return null;
|
|
218
|
+
}
|
|
219
|
+
}, [enabled, initOptions]);
|
|
220
|
+
useEffect(() => {
|
|
221
|
+
if (!enabled) {
|
|
222
|
+
return;
|
|
223
|
+
}
|
|
224
|
+
void runInit();
|
|
225
|
+
}, [enabled, runInit]);
|
|
226
|
+
return {
|
|
227
|
+
status,
|
|
228
|
+
session,
|
|
229
|
+
error,
|
|
230
|
+
reload: runInit
|
|
231
|
+
};
|
|
232
|
+
};
|
|
233
|
+
|
|
234
|
+
// src/vitraun-try-on.jsx
|
|
235
|
+
import { useEffect as useEffect2, useMemo as useMemo2 } from "react";
|
|
236
|
+
import { ActivityIndicator, StyleSheet, Text, View } from "react-native";
|
|
237
|
+
import WebView from "react-native-webview";
|
|
238
|
+
import { jsx } from "react/jsx-runtime";
|
|
239
|
+
var styles = StyleSheet.create({
|
|
240
|
+
container: {
|
|
241
|
+
flex: 1
|
|
242
|
+
},
|
|
243
|
+
center: {
|
|
244
|
+
flex: 1,
|
|
245
|
+
alignItems: "center",
|
|
246
|
+
justifyContent: "center",
|
|
247
|
+
padding: 24
|
|
248
|
+
},
|
|
249
|
+
errorText: {
|
|
250
|
+
color: "#b00020",
|
|
251
|
+
textAlign: "center"
|
|
252
|
+
}
|
|
253
|
+
});
|
|
254
|
+
var VitraunTryOn = (props) => {
|
|
255
|
+
const {
|
|
256
|
+
merchantId,
|
|
257
|
+
widgetId,
|
|
258
|
+
lang,
|
|
259
|
+
env,
|
|
260
|
+
apiPort,
|
|
261
|
+
appPort,
|
|
262
|
+
isolatedSku,
|
|
263
|
+
applySkus,
|
|
264
|
+
flow,
|
|
265
|
+
basketOpensIn,
|
|
266
|
+
checkoutOpensIn,
|
|
267
|
+
useSimplePage,
|
|
268
|
+
showDetails,
|
|
269
|
+
showProductPrice,
|
|
270
|
+
priceFrom,
|
|
271
|
+
priceTo,
|
|
272
|
+
currencySymbol,
|
|
273
|
+
isSimulationMode,
|
|
274
|
+
platform,
|
|
275
|
+
bundleId,
|
|
276
|
+
packageName,
|
|
277
|
+
appId,
|
|
278
|
+
appVersion,
|
|
279
|
+
attestationToken,
|
|
280
|
+
embedParentOrigin,
|
|
281
|
+
pageUrl,
|
|
282
|
+
referrer,
|
|
283
|
+
userAgent,
|
|
284
|
+
timezone,
|
|
285
|
+
initTimeoutMs,
|
|
286
|
+
autoInit = true,
|
|
287
|
+
onEvent,
|
|
288
|
+
onError,
|
|
289
|
+
onReady,
|
|
290
|
+
style
|
|
291
|
+
} = props;
|
|
292
|
+
const embedState = useMemo2(
|
|
293
|
+
() => buildEmbedInitStateFromProps({
|
|
294
|
+
merchantId,
|
|
295
|
+
widgetId,
|
|
296
|
+
lang,
|
|
297
|
+
env,
|
|
298
|
+
apiPort,
|
|
299
|
+
appPort,
|
|
300
|
+
isSimulationMode,
|
|
301
|
+
platform,
|
|
302
|
+
bundleId,
|
|
303
|
+
packageName,
|
|
304
|
+
appId,
|
|
305
|
+
appVersion,
|
|
306
|
+
attestationToken,
|
|
307
|
+
embedParentOrigin,
|
|
308
|
+
pageUrl,
|
|
309
|
+
referrer,
|
|
310
|
+
userAgent,
|
|
311
|
+
timezone
|
|
312
|
+
}),
|
|
313
|
+
[
|
|
314
|
+
merchantId,
|
|
315
|
+
widgetId,
|
|
316
|
+
lang,
|
|
317
|
+
env,
|
|
318
|
+
apiPort,
|
|
319
|
+
appPort,
|
|
320
|
+
isSimulationMode,
|
|
321
|
+
platform,
|
|
322
|
+
bundleId,
|
|
323
|
+
packageName,
|
|
324
|
+
appId,
|
|
325
|
+
appVersion,
|
|
326
|
+
attestationToken,
|
|
327
|
+
embedParentOrigin,
|
|
328
|
+
pageUrl,
|
|
329
|
+
referrer,
|
|
330
|
+
userAgent,
|
|
331
|
+
timezone
|
|
332
|
+
]
|
|
333
|
+
);
|
|
334
|
+
const { status, session, error } = useVitraunInit({
|
|
335
|
+
enabled: autoInit,
|
|
336
|
+
state: embedState,
|
|
337
|
+
timeoutMs: initTimeoutMs
|
|
338
|
+
});
|
|
339
|
+
const injectedScript = useMemo2(
|
|
340
|
+
() => buildInjectedJavaScriptBeforeContentLoaded(
|
|
341
|
+
buildNativeConfigOverrides({
|
|
342
|
+
basketOpensIn,
|
|
343
|
+
checkoutOpensIn,
|
|
344
|
+
flow,
|
|
345
|
+
useSimplePage,
|
|
346
|
+
showDetails,
|
|
347
|
+
showProductPrice,
|
|
348
|
+
priceFrom,
|
|
349
|
+
priceTo,
|
|
350
|
+
currencySymbol,
|
|
351
|
+
isolatedSku,
|
|
352
|
+
applySkus,
|
|
353
|
+
isSimulationMode
|
|
354
|
+
})
|
|
355
|
+
),
|
|
356
|
+
[
|
|
357
|
+
basketOpensIn,
|
|
358
|
+
checkoutOpensIn,
|
|
359
|
+
flow,
|
|
360
|
+
useSimplePage,
|
|
361
|
+
showDetails,
|
|
362
|
+
showProductPrice,
|
|
363
|
+
priceFrom,
|
|
364
|
+
priceTo,
|
|
365
|
+
currencySymbol,
|
|
366
|
+
isolatedSku,
|
|
367
|
+
applySkus,
|
|
368
|
+
isSimulationMode
|
|
369
|
+
]
|
|
370
|
+
);
|
|
371
|
+
useEffect2(() => {
|
|
372
|
+
if (status === "ready" && typeof onReady === "function") {
|
|
373
|
+
onReady();
|
|
374
|
+
}
|
|
375
|
+
}, [status, onReady]);
|
|
376
|
+
useEffect2(() => {
|
|
377
|
+
if (status === "error" && error && typeof onError === "function") {
|
|
378
|
+
onError(error);
|
|
379
|
+
}
|
|
380
|
+
}, [status, error, onError]);
|
|
381
|
+
if (status === "loading" || status === "idle") {
|
|
382
|
+
return /* @__PURE__ */ jsx(View, { style: [styles.center, style], accessibilityRole: "progressbar", children: /* @__PURE__ */ jsx(ActivityIndicator, { size: "large" }) });
|
|
383
|
+
}
|
|
384
|
+
if (status === "error" || !session?.vtoUrl) {
|
|
385
|
+
const message = error?.message ?? "Could not start the virtual try-on. Please try again.";
|
|
386
|
+
return /* @__PURE__ */ jsx(View, { style: [styles.center, style], accessibilityRole: "alert", children: /* @__PURE__ */ jsx(Text, { style: styles.errorText, children: message }) });
|
|
387
|
+
}
|
|
388
|
+
return /* @__PURE__ */ jsx(View, { style: [styles.container, style], children: /* @__PURE__ */ jsx(
|
|
389
|
+
WebView,
|
|
390
|
+
{
|
|
391
|
+
source: { uri: session.vtoUrl },
|
|
392
|
+
style: styles.container,
|
|
393
|
+
mediaPlaybackRequiresUserAction: false,
|
|
394
|
+
allowsInlineMediaPlayback: true,
|
|
395
|
+
javaScriptEnabled: true,
|
|
396
|
+
domStorageEnabled: true,
|
|
397
|
+
injectedJavaScriptBeforeContentLoaded: injectedScript,
|
|
398
|
+
onMessage: (event) => {
|
|
399
|
+
handleVitraunWebViewMessage(event.nativeEvent.data, onEvent);
|
|
400
|
+
}
|
|
401
|
+
}
|
|
402
|
+
) });
|
|
403
|
+
};
|
|
404
|
+
export {
|
|
405
|
+
VITRAUN_VTO_DEFAULT_EVENT_TYPES2 as VITRAUN_VTO_DEFAULT_EVENT_TYPES,
|
|
406
|
+
VITRAUN_VTO_EXTRA_EVENT_TYPES,
|
|
407
|
+
VitraunTryOn,
|
|
408
|
+
buildEmbedInitStateFromProps,
|
|
409
|
+
buildInjectedBridgeScript,
|
|
410
|
+
buildInjectedJavaScriptBeforeContentLoaded,
|
|
411
|
+
buildNativeConfigInjectScript,
|
|
412
|
+
buildNativeConfigOverrides,
|
|
413
|
+
handleVitraunWebViewMessage,
|
|
414
|
+
initializeVitraunSession,
|
|
415
|
+
parseVitraunBridgeMessage,
|
|
416
|
+
postEmbedInit2 as postEmbedInit,
|
|
417
|
+
useVitraunInit
|
|
418
|
+
};
|
package/package.json
ADDED
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@vitraun/react-native",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Vitraun Try-On React Native adapter (WebView + embed-init bridge)",
|
|
5
|
+
"license": "SEE LICENSE IN LICENSE.txt",
|
|
6
|
+
"repository": {
|
|
7
|
+
"type": "git",
|
|
8
|
+
"url": "https://github.com/clagils/tryon-new-version.git",
|
|
9
|
+
"directory": "vto-npm/react-native"
|
|
10
|
+
},
|
|
11
|
+
"homepage": "https://github.com/clagils/tryon-new-version/tree/main/vto-npm/react-native",
|
|
12
|
+
"bugs": {
|
|
13
|
+
"url": "https://github.com/clagils/tryon-new-version/issues"
|
|
14
|
+
},
|
|
15
|
+
"publishConfig": {
|
|
16
|
+
"access": "public"
|
|
17
|
+
},
|
|
18
|
+
"private": false,
|
|
19
|
+
"type": "module",
|
|
20
|
+
"main": "./dist/index.js",
|
|
21
|
+
"module": "./dist/index.js",
|
|
22
|
+
"types": "./dist/index.d.ts",
|
|
23
|
+
"files": [
|
|
24
|
+
"LICENSE.txt",
|
|
25
|
+
"dist",
|
|
26
|
+
"README.md"
|
|
27
|
+
],
|
|
28
|
+
"scripts": {
|
|
29
|
+
"build": "node ./scripts/build.mjs",
|
|
30
|
+
"clean": "rm -rf dist",
|
|
31
|
+
"test": "vitest run"
|
|
32
|
+
},
|
|
33
|
+
"dependencies": {
|
|
34
|
+
"@vitraun/core": "^0.2.0"
|
|
35
|
+
},
|
|
36
|
+
"peerDependencies": {
|
|
37
|
+
"react": ">=18",
|
|
38
|
+
"react-native": ">=0.72",
|
|
39
|
+
"react-native-webview": ">=13"
|
|
40
|
+
},
|
|
41
|
+
"devDependencies": {
|
|
42
|
+
"@babel/core": "^7.28.0",
|
|
43
|
+
"@babel/preset-react": "^7.27.1",
|
|
44
|
+
"esbuild": "^0.25.9",
|
|
45
|
+
"react": "^19.2.5",
|
|
46
|
+
"vitest": "^3.2.4"
|
|
47
|
+
}
|
|
48
|
+
}
|