@myop/react-native 0.0.1

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,166 @@
1
+ # @myop/react-native-host
2
+
3
+ A React Native library for embedding Myop components via WebView.
4
+
5
+ ## Installation
6
+
7
+ ```bash
8
+ npm install @myop/react-native-host
9
+ ```
10
+
11
+ ### Peer Dependencies
12
+
13
+ Make sure you have the required peer dependencies installed:
14
+
15
+ ```bash
16
+ npm install react-native-webview
17
+ ```
18
+
19
+ ## Usage
20
+
21
+ ### Basic Usage with Component ID
22
+
23
+ ```tsx
24
+ import React from 'react';
25
+ import { View } from 'react-native';
26
+ import { MyopComponent } from '@myop/react-native-host';
27
+
28
+ export default function App() {
29
+ return (
30
+ <View style={{ flex: 1 }}>
31
+ <MyopComponent
32
+ componentId="your-component-id"
33
+ style={{ flex: 1 }}
34
+ />
35
+ </View>
36
+ );
37
+ }
38
+ ```
39
+
40
+ ### Usage with Component Config
41
+
42
+ ```tsx
43
+ import React from 'react';
44
+ import { View } from 'react-native';
45
+ import { MyopComponent, IComponentInstanceConfig } from '@myop/react-native-host';
46
+
47
+ export default function App() {
48
+ const componentConfig: IComponentInstanceConfig = {
49
+ id: 'component-instance-id',
50
+ componentId: 'your-component-id',
51
+ componentName: 'MyComponent',
52
+ skinSelector: {
53
+ // your skin selector config
54
+ }
55
+ };
56
+
57
+ return (
58
+ <View style={{ flex: 1 }}>
59
+ <MyopComponent
60
+ componentConfig={componentConfig}
61
+ style={{ flex: 1 }}
62
+ />
63
+ </View>
64
+ );
65
+ }
66
+ ```
67
+
68
+ ### With onLoad Callback
69
+
70
+ The `onLoad` callback gives you access to the component instance after it loads, allowing you to execute commands:
71
+
72
+ ```tsx
73
+ import React from 'react';
74
+ import { View, Button } from 'react-native';
75
+ import { MyopComponent } from '@myop/react-native-host';
76
+
77
+ export default function App() {
78
+ const [myopInstance, setMyopInstance] = React.useState(null);
79
+
80
+ const handleLoad = (myopComponent) => {
81
+ setMyopInstance(() => myopComponent);
82
+ console.log('Myop component loaded!');
83
+ };
84
+
85
+ const executeCommand = () => {
86
+ if (myopInstance) {
87
+ myopInstance('.someMethod()');
88
+ }
89
+ };
90
+
91
+ return (
92
+ <View style={{ flex: 1 }}>
93
+ <MyopComponent
94
+ componentId="your-component-id"
95
+ onLoad={handleLoad}
96
+ style={{ flex: 1 }}
97
+ />
98
+ <Button title="Execute Command" onPress={executeCommand} />
99
+ </View>
100
+ );
101
+ }
102
+ ```
103
+
104
+ ## API
105
+
106
+ ### Props
107
+
108
+ | Prop | Type | Required | Description |
109
+ |------|------|----------|-------------|
110
+ | `componentId` | `string` | No* | The ID of the component to load from Myop cloud |
111
+ | `componentConfig` | `IComponentInstanceConfig` | No* | The complete component configuration object |
112
+ | `style` | `StyleProp<ViewStyle>` | No | Custom styles for the component container |
113
+ | `onLoad` | `(myopComponent: (command: string) => void) => void` | No | Callback fired when component loads, receives command executor function |
114
+
115
+ \* Either `componentId` or `componentConfig` must be provided
116
+
117
+ ### Types
118
+
119
+ #### IComponentInstanceConfig
120
+
121
+ ```typescript
122
+ interface IComponentInstanceConfig {
123
+ id: string;
124
+ componentId: string;
125
+ componentName: string;
126
+ skinSelector: ISkinSelectorConfig;
127
+ nestedComponents?: IComponentInstanceConfig[];
128
+ resolvedExperiences?: IExperience[];
129
+ resolvedNestedComponents?: IComponentConfig[];
130
+ [key: string]: any;
131
+ }
132
+ ```
133
+
134
+ ## How it Works
135
+
136
+ The component uses a WebView to load and render Myop components. It:
137
+
138
+ 1. Loads the Myop SDK from the CDN
139
+ 2. Fetches the component configuration (if using `componentId`)
140
+ 3. Initializes the component inside the WebView
141
+ 4. Provides a bridge to execute commands on the loaded component
142
+
143
+ ## Requirements
144
+
145
+ - React Native 0.60.0 or higher
146
+ - React 16.8.0 or higher
147
+ - react-native-webview 13.0.0 or higher
148
+
149
+ ## Development
150
+
151
+ This project includes a demo Expo app for testing. To run the development app:
152
+
153
+ ```bash
154
+ npm install
155
+ npx expo start
156
+ ```
157
+
158
+ ## Building the Library
159
+
160
+ ```bash
161
+ npm run build
162
+ ```
163
+
164
+ ## License
165
+
166
+ MIT
@@ -0,0 +1,12 @@
1
+ import React from 'react';
2
+ import { StyleProp, ViewStyle } from 'react-native';
3
+ import type { IComponentInstanceConfig } from './types';
4
+ interface IPropTypes {
5
+ style?: StyleProp<ViewStyle> | undefined;
6
+ componentId?: string;
7
+ componentConfig?: IComponentInstanceConfig;
8
+ onLoad?: (myopComponent: (command: string) => void) => void;
9
+ }
10
+ export declare const MyopComponent: (props: IPropTypes) => React.JSX.Element;
11
+ export {};
12
+ //# sourceMappingURL=MyopComponent.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"MyopComponent.d.ts","sourceRoot":"","sources":["../src/MyopComponent.tsx"],"names":[],"mappings":"AAAA,OAAO,KAA0B,MAAM,OAAO,CAAC;AAG/C,OAAO,EAAC,SAAS,EAAE,SAAS,EAAC,MAAM,cAAc,CAAC;AAClD,OAAO,KAAK,EAAC,wBAAwB,EAAC,MAAM,SAAS,CAAC;AAGtD,UAAU,UAAU;IAChB,KAAK,CAAC,EAAE,SAAS,CAAC,SAAS,CAAC,GAAG,SAAS,CAAC;IACzC,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,eAAe,CAAC,EAAE,wBAAwB,CAAC;IAC3C,MAAM,CAAC,EAAE,CAAC,aAAa,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,KAAK,IAAI,CAAC;CAC/D;AAED,eAAO,MAAM,aAAa,GAAI,OAAO,UAAU,sBAqE9C,CAAA"}
@@ -0,0 +1,102 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ exports.MyopComponent = void 0;
37
+ const react_1 = __importStar(require("react"));
38
+ const react_native_1 = require("react-native");
39
+ const react_native_webview_1 = require("react-native-webview");
40
+ const componentHost_html_1 = require("./componentHost.html");
41
+ const MyopComponent = (props) => {
42
+ const webviewRef = (0, react_1.useRef)(null);
43
+ const myopComponent = (command) => {
44
+ var _a;
45
+ //TODO : return promise to data?
46
+ (_a = webviewRef.current) === null || _a === void 0 ? void 0 : _a.injectJavaScript(`
47
+ window.myopComponent${command}
48
+ `);
49
+ };
50
+ const onMessage = (event) => {
51
+ if (event.nativeEvent.data === 'COMPONENT_LOADED') {
52
+ if (props.onLoad) {
53
+ props.onLoad(myopComponent);
54
+ }
55
+ // webviewRef.current?.injectJavaScript(`
56
+ // window.myopComponent.props.showPopupWOW();
57
+ // `);
58
+ }
59
+ // Alert.alert('Received from WebView', event.nativeEvent.data);
60
+ };
61
+ const fetchFromReactNative = async () => {
62
+ var _a;
63
+ try {
64
+ let componentConfig = null;
65
+ if (props.componentConfig) {
66
+ componentConfig = props.componentConfig;
67
+ }
68
+ else if (props.componentId) {
69
+ const res = await fetch(`https://cloud.myop.dev/flow?id=${props.componentId}&auto=true`);
70
+ componentConfig = await res.json();
71
+ componentConfig = componentConfig.item.components[0];
72
+ }
73
+ const encoded = encodeURIComponent(JSON.stringify(componentConfig));
74
+ //send it into the webview
75
+ (_a = webviewRef.current) === null || _a === void 0 ? void 0 : _a.injectJavaScript(`
76
+ loadMyopComponent(\`${encoded}\`);
77
+ `);
78
+ }
79
+ catch (err) {
80
+ console.error('Fetch failed:', err);
81
+ }
82
+ };
83
+ (0, react_1.useEffect)(() => {
84
+ if (webviewRef.current)
85
+ fetchFromReactNative().then();
86
+ }, [webviewRef]);
87
+ return (react_1.default.createElement(react_native_1.View, { style: props.style ? props.style : styles.root },
88
+ react_1.default.createElement(react_native_webview_1.WebView, { ref: webviewRef, originWhitelist: ['*'], source: { html: componentHost_html_1.HTML }, onMessage: onMessage, style: styles.webview, javaScriptEnabled: true, domStorageEnabled: true, mixedContentMode: "always" // allows HTTPS + HTTP content
89
+ , allowFileAccess: true, allowUniversalAccessFromFileURLs: true })));
90
+ };
91
+ exports.MyopComponent = MyopComponent;
92
+ const styles = react_native_1.StyleSheet.create({
93
+ root: {
94
+ flex: 1,
95
+ // backgroundColor: 'red', // visible background
96
+ },
97
+ webview: {
98
+ flex: 1,
99
+ //backgroundColor: 'blue', // visible background behind HTML
100
+ }
101
+ });
102
+ //# sourceMappingURL=MyopComponent.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"MyopComponent.js","sourceRoot":"","sources":["../src/MyopComponent.tsx"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export declare const HTML = "\n <!DOCTYPE html>\n <html>\n <head>\n <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n <style>\n html, body {\n margin: 0;\n padding: 0;\n width: 100%;\n height: 100%;\n // background: #ffeb3b;\n display: flex;\n flex-direction: column;\n justify-content: center;\n align-items: center;\n font-family: sans-serif;\n }\n \n #myop-container{\n margin: 0;\n padding: 0;\n width: 100%;\n height: 100%;\n }\n </style>\n \n <script src=\"https://cdn.myop.dev/sdk/next/myop_sdk.min.js\"></script>\n\n </head>\n <body>\n <div id=\"myop-container\">Loading</div>\n <script>\n \n async function loadMyopComponent(configAsString) {\n const componentConfig = JSON.parse(decodeURIComponent(configAsString));\n //alert('loadMyopComponent');\n const { hostSDK } = await window.myop.rootSDK.getHostModule();\n const container = document.getElementById('myop-container');\n //alert(container)\n window.myopComponent = await hostSDK.loadComponent(componentConfig, container); \n window.ReactNativeWebView.postMessage('COMPONENT_LOADED');\n } \n </script>\n </body>\n </html>\n\n";
2
+ //# sourceMappingURL=componentHost.html.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"componentHost.html.d.ts","sourceRoot":"","sources":["../src/componentHost.html.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,IAAI,s7CA+ChB,CAAC"}
@@ -0,0 +1,52 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.HTML = void 0;
4
+ exports.HTML = `
5
+ <!DOCTYPE html>
6
+ <html>
7
+ <head>
8
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
9
+ <style>
10
+ html, body {
11
+ margin: 0;
12
+ padding: 0;
13
+ width: 100%;
14
+ height: 100%;
15
+ // background: #ffeb3b;
16
+ display: flex;
17
+ flex-direction: column;
18
+ justify-content: center;
19
+ align-items: center;
20
+ font-family: sans-serif;
21
+ }
22
+
23
+ #myop-container{
24
+ margin: 0;
25
+ padding: 0;
26
+ width: 100%;
27
+ height: 100%;
28
+ }
29
+ </style>
30
+
31
+ <script src="https://cdn.myop.dev/sdk/next/myop_sdk.min.js"></script>
32
+
33
+ </head>
34
+ <body>
35
+ <div id="myop-container">Loading</div>
36
+ <script>
37
+
38
+ async function loadMyopComponent(configAsString) {
39
+ const componentConfig = JSON.parse(decodeURIComponent(configAsString));
40
+ //alert('loadMyopComponent');
41
+ const { hostSDK } = await window.myop.rootSDK.getHostModule();
42
+ const container = document.getElementById('myop-container');
43
+ //alert(container)
44
+ window.myopComponent = await hostSDK.loadComponent(componentConfig, container);
45
+ window.ReactNativeWebView.postMessage('COMPONENT_LOADED');
46
+ }
47
+ </script>
48
+ </body>
49
+ </html>
50
+
51
+ `;
52
+ //# sourceMappingURL=componentHost.html.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"componentHost.html.js","sourceRoot":"","sources":["../src/componentHost.html.ts"],"names":[],"mappings":";;;AAAa,QAAA,IAAI,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA+CnB,CAAC"}
@@ -0,0 +1,3 @@
1
+ export { MyopComponent } from './MyopComponent';
2
+ export type { IComponentInstanceConfig } from './types';
3
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAChD,YAAY,EAAE,wBAAwB,EAAE,MAAM,SAAS,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,6 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.MyopComponent = void 0;
4
+ var MyopComponent_1 = require("./MyopComponent");
5
+ Object.defineProperty(exports, "MyopComponent", { enumerable: true, get: function () { return MyopComponent_1.MyopComponent; } });
6
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;AAAA,iDAAgD;AAAvC,8GAAA,aAAa,OAAA"}
@@ -0,0 +1,20 @@
1
+ export interface ISkinSelectorConfig {
2
+ [key: string]: any;
3
+ }
4
+ export interface IExperience {
5
+ [key: string]: any;
6
+ }
7
+ export interface IComponentConfig {
8
+ [key: string]: any;
9
+ }
10
+ export interface IComponentInstanceConfig {
11
+ id: string;
12
+ componentId: string;
13
+ componentName: string;
14
+ skinSelector: ISkinSelectorConfig;
15
+ nestedComponents?: IComponentInstanceConfig[];
16
+ resolvedExperiences?: IExperience[];
17
+ resolvedNestedComponents?: IComponentConfig[];
18
+ [key: string]: any;
19
+ }
20
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAGA,MAAM,WAAW,mBAAmB;IAChC,CAAC,GAAG,EAAE,MAAM,GAAG,GAAG,CAAC;CACtB;AAED,MAAM,WAAW,WAAW;IACxB,CAAC,GAAG,EAAE,MAAM,GAAG,GAAG,CAAC;CACtB;AAED,MAAM,WAAW,gBAAgB;IAC7B,CAAC,GAAG,EAAE,MAAM,GAAG,GAAG,CAAC;CACtB;AAED,MAAM,WAAW,wBAAwB;IACrC,EAAE,EAAE,MAAM,CAAC;IACX,WAAW,EAAE,MAAM,CAAC;IACpB,aAAa,EAAE,MAAM,CAAC;IACtB,YAAY,EAAE,mBAAmB,CAAC;IAClC,gBAAgB,CAAC,EAAE,wBAAwB,EAAE,CAAC;IAC9C,mBAAmB,CAAC,EAAE,WAAW,EAAE,CAAC;IACpC,wBAAwB,CAAC,EAAE,gBAAgB,EAAE,CAAC;IAC9C,CAAC,GAAG,EAAE,MAAM,GAAG,GAAG,CAAC;CACtB"}
package/dist/types.js ADDED
@@ -0,0 +1,5 @@
1
+ "use strict";
2
+ // Type definitions for Myop Component configuration
3
+ // These types should match the types from myop-sdk
4
+ Object.defineProperty(exports, "__esModule", { value: true });
5
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":";AAAA,oDAAoD;AACpD,mDAAmD"}
package/package.json ADDED
@@ -0,0 +1,74 @@
1
+ {
2
+ "name": "@myop/react-native",
3
+ "version": "0.0.1",
4
+ "description": "React Native component for embedding Myop components via WebView",
5
+ "main": "./dist/index.js",
6
+ "types": "./dist/index.d.ts",
7
+ "files": [
8
+ "dist",
9
+ "src",
10
+ "README.md"
11
+ ],
12
+ "scripts": {
13
+ "build": "tsc --project tsconfig.lib.json",
14
+ "prepare": "npm run build",
15
+ "clean": "rm -rf dist",
16
+ "start": "expo start",
17
+ "reset-project": "node ./scripts/reset-project.js",
18
+ "android": "expo start --android",
19
+ "ios": "expo start --ios",
20
+ "web": "expo start --web",
21
+ "lint": "expo lint",
22
+ "release": "npm publish --access public"
23
+ },
24
+ "peerDependencies": {
25
+ "react": ">=16.8.0",
26
+ "react-native": ">=0.60.0",
27
+ "react-native-webview": ">=13.0.0"
28
+ },
29
+ "devDependencies": {
30
+ "@types/react": "~19.1.0",
31
+ "@types/react-native": "^0.73.0",
32
+ "typescript": "~5.9.2",
33
+ "eslint": "^9.25.0",
34
+ "eslint-config-expo": "~10.0.0",
35
+ "react": "19.1.0",
36
+ "react-native": "0.81.4",
37
+ "react-native-webview": "^13.16.0",
38
+ "@expo/vector-icons": "^15.0.2",
39
+ "@react-navigation/bottom-tabs": "^7.4.0",
40
+ "@react-navigation/elements": "^2.6.3",
41
+ "@react-navigation/native": "^7.1.8",
42
+ "expo": "~54.0.12",
43
+ "expo-constants": "~18.0.9",
44
+ "expo-font": "~14.0.8",
45
+ "expo-haptics": "~15.0.7",
46
+ "expo-image": "~3.0.8",
47
+ "expo-linking": "~8.0.8",
48
+ "expo-router": "~6.0.10",
49
+ "expo-splash-screen": "~31.0.10",
50
+ "expo-status-bar": "~3.0.8",
51
+ "expo-symbols": "~1.0.7",
52
+ "expo-system-ui": "~6.0.7",
53
+ "expo-web-browser": "~15.0.8",
54
+ "react-dom": "19.1.0",
55
+ "react-native-gesture-handler": "~2.28.0",
56
+ "react-native-worklets": "0.5.1",
57
+ "react-native-reanimated": "~4.1.1",
58
+ "react-native-safe-area-context": "~5.6.0",
59
+ "react-native-screens": "~4.16.0",
60
+ "react-native-web": "~0.21.0"
61
+ },
62
+ "keywords": [
63
+ "react-native",
64
+ "myop",
65
+ "webview",
66
+ "component"
67
+ ],
68
+ "author": "",
69
+ "license": "MIT",
70
+ "repository": {
71
+ "type": "git",
72
+ "url": ""
73
+ }
74
+ }
@@ -0,0 +1,95 @@
1
+ import React, {useEffect, useRef} from 'react';
2
+ import {View, StyleSheet} from 'react-native';
3
+ import {WebView} from 'react-native-webview';
4
+ import {StyleProp, ViewStyle} from 'react-native';
5
+ import type {IComponentInstanceConfig} from './types';
6
+ import {HTML} from './componentHost.html';
7
+
8
+ interface IPropTypes {
9
+ style?: StyleProp<ViewStyle> | undefined;
10
+ componentId?: string;
11
+ componentConfig?: IComponentInstanceConfig;
12
+ onLoad?: (myopComponent: (command: string) => void) => void;
13
+ }
14
+
15
+ export const MyopComponent = (props: IPropTypes) => {
16
+ const webviewRef = useRef<WebView>(null);
17
+
18
+ const myopComponent = (command: string) => {
19
+ //TODO : return promise to data?
20
+ webviewRef.current?.injectJavaScript(`
21
+ window.myopComponent${command}
22
+ `);
23
+ }
24
+
25
+ const onMessage = (event: any) => {
26
+ if (event.nativeEvent.data === 'COMPONENT_LOADED') {
27
+ if (props.onLoad) {
28
+ props.onLoad(myopComponent);
29
+ }
30
+ // webviewRef.current?.injectJavaScript(`
31
+ // window.myopComponent.props.showPopupWOW();
32
+ // `);
33
+ }
34
+ // Alert.alert('Received from WebView', event.nativeEvent.data);
35
+ };
36
+
37
+
38
+ const fetchFromReactNative = async () => {
39
+ try {
40
+
41
+ let componentConfig = null;
42
+
43
+ if (props.componentConfig) {
44
+ componentConfig = props.componentConfig;
45
+ } else if (props.componentId) {
46
+ const res = await fetch(`https://cloud.myop.dev/flow?id=${props.componentId!}&auto=true`);
47
+ componentConfig = await res.json();
48
+ componentConfig = componentConfig.item.components[0];
49
+ }
50
+
51
+ const encoded = encodeURIComponent(JSON.stringify(componentConfig));
52
+
53
+ //send it into the webview
54
+ webviewRef.current?.injectJavaScript(`
55
+ loadMyopComponent(\`${encoded}\`);
56
+ `);
57
+
58
+ } catch (err) {
59
+ console.error('Fetch failed:', err);
60
+ }
61
+ };
62
+
63
+ useEffect(() => {
64
+ if (webviewRef.current)
65
+ fetchFromReactNative().then();
66
+ }, [webviewRef]);
67
+
68
+ return (
69
+ <View style={props.style ? props.style : styles.root}>
70
+ <WebView
71
+ ref={webviewRef}
72
+ originWhitelist={['*']}
73
+ source={{html: HTML}}
74
+ onMessage={onMessage}
75
+ style={styles.webview}
76
+ javaScriptEnabled={true}
77
+ domStorageEnabled={true} // allows localStorage, etc.
78
+ mixedContentMode="always" // allows HTTPS + HTTP content
79
+ allowFileAccess={true} // allows access to file:// if needed
80
+ allowUniversalAccessFromFileURLs={true} // allows requests when loaded from a local file
81
+ />
82
+ </View>
83
+ );
84
+ }
85
+
86
+ const styles = StyleSheet.create({
87
+ root: {
88
+ flex: 1,
89
+ // backgroundColor: 'red', // visible background
90
+ },
91
+ webview: {
92
+ flex: 1,
93
+ //backgroundColor: 'blue', // visible background behind HTML
94
+ }
95
+ });
@@ -0,0 +1,48 @@
1
+ export const HTML = `
2
+ <!DOCTYPE html>
3
+ <html>
4
+ <head>
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
+ <style>
7
+ html, body {
8
+ margin: 0;
9
+ padding: 0;
10
+ width: 100%;
11
+ height: 100%;
12
+ // background: #ffeb3b;
13
+ display: flex;
14
+ flex-direction: column;
15
+ justify-content: center;
16
+ align-items: center;
17
+ font-family: sans-serif;
18
+ }
19
+
20
+ #myop-container{
21
+ margin: 0;
22
+ padding: 0;
23
+ width: 100%;
24
+ height: 100%;
25
+ }
26
+ </style>
27
+
28
+ <script src="https://cdn.myop.dev/sdk/next/myop_sdk.min.js"></script>
29
+
30
+ </head>
31
+ <body>
32
+ <div id="myop-container">Loading</div>
33
+ <script>
34
+
35
+ async function loadMyopComponent(configAsString) {
36
+ const componentConfig = JSON.parse(decodeURIComponent(configAsString));
37
+ //alert('loadMyopComponent');
38
+ const { hostSDK } = await window.myop.rootSDK.getHostModule();
39
+ const container = document.getElementById('myop-container');
40
+ //alert(container)
41
+ window.myopComponent = await hostSDK.loadComponent(componentConfig, container);
42
+ window.ReactNativeWebView.postMessage('COMPONENT_LOADED');
43
+ }
44
+ </script>
45
+ </body>
46
+ </html>
47
+
48
+ `;
package/src/index.ts ADDED
@@ -0,0 +1,2 @@
1
+ export { MyopComponent } from './MyopComponent';
2
+ export type { IComponentInstanceConfig } from './types';
package/src/types.ts ADDED
@@ -0,0 +1,25 @@
1
+ // Type definitions for Myop Component configuration
2
+ // These types should match the types from myop-sdk
3
+
4
+ export interface ISkinSelectorConfig {
5
+ [key: string]: any;
6
+ }
7
+
8
+ export interface IExperience {
9
+ [key: string]: any;
10
+ }
11
+
12
+ export interface IComponentConfig {
13
+ [key: string]: any;
14
+ }
15
+
16
+ export interface IComponentInstanceConfig {
17
+ id: string;
18
+ componentId: string;
19
+ componentName: string;
20
+ skinSelector: ISkinSelectorConfig;
21
+ nestedComponents?: IComponentInstanceConfig[];
22
+ resolvedExperiences?: IExperience[];
23
+ resolvedNestedComponents?: IComponentConfig[];
24
+ [key: string]: any;
25
+ }