@menuia/react-native 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.
@@ -0,0 +1,42 @@
1
+ import * as react_jsx_runtime from 'react/jsx-runtime';
2
+ export { ChatMessage, ConnectionStatus, MenuIAClient, MenuIAConfig } from '@menuia/core';
3
+
4
+ interface MenuIAChatProps {
5
+ /** Widget ID (from /dashboard/channels) - preferred */
6
+ widgetId?: string;
7
+ /** Agent ID (from /dashboard/agents) - fallback */
8
+ agentId?: string;
9
+ /** API base URL */
10
+ apiUrl?: string;
11
+ /** Primary color (hex) */
12
+ primaryColor?: string;
13
+ /** Position of the floating button */
14
+ position?: 'bottom-right' | 'bottom-left';
15
+ /** Bubble size in pixels */
16
+ bubbleSize?: number;
17
+ /** Bubble margin from edges */
18
+ bubbleMargin?: number;
19
+ /** Start with chat open */
20
+ defaultOpen?: boolean;
21
+ /** Show as inline (no floating button, fills container) */
22
+ inline?: boolean;
23
+ /** User metadata */
24
+ metadata?: {
25
+ name?: string;
26
+ email?: string;
27
+ phone?: string;
28
+ [key: string]: unknown;
29
+ };
30
+ /** Custom fields for AI tools */
31
+ customFields?: Record<string, string>;
32
+ /** Callback when new message received */
33
+ onMessage?: (message: {
34
+ role: string;
35
+ content: string;
36
+ }) => void;
37
+ /** Callback when chat opens/closes */
38
+ onToggle?: (isOpen: boolean) => void;
39
+ }
40
+ declare function MenuIAChat({ widgetId, agentId, apiUrl, primaryColor, position, bubbleSize, bubbleMargin, defaultOpen, inline, metadata, customFields, onMessage, onToggle, }: MenuIAChatProps): react_jsx_runtime.JSX.Element | null;
41
+
42
+ export { MenuIAChat, type MenuIAChatProps };
@@ -0,0 +1,42 @@
1
+ import * as react_jsx_runtime from 'react/jsx-runtime';
2
+ export { ChatMessage, ConnectionStatus, MenuIAClient, MenuIAConfig } from '@menuia/core';
3
+
4
+ interface MenuIAChatProps {
5
+ /** Widget ID (from /dashboard/channels) - preferred */
6
+ widgetId?: string;
7
+ /** Agent ID (from /dashboard/agents) - fallback */
8
+ agentId?: string;
9
+ /** API base URL */
10
+ apiUrl?: string;
11
+ /** Primary color (hex) */
12
+ primaryColor?: string;
13
+ /** Position of the floating button */
14
+ position?: 'bottom-right' | 'bottom-left';
15
+ /** Bubble size in pixels */
16
+ bubbleSize?: number;
17
+ /** Bubble margin from edges */
18
+ bubbleMargin?: number;
19
+ /** Start with chat open */
20
+ defaultOpen?: boolean;
21
+ /** Show as inline (no floating button, fills container) */
22
+ inline?: boolean;
23
+ /** User metadata */
24
+ metadata?: {
25
+ name?: string;
26
+ email?: string;
27
+ phone?: string;
28
+ [key: string]: unknown;
29
+ };
30
+ /** Custom fields for AI tools */
31
+ customFields?: Record<string, string>;
32
+ /** Callback when new message received */
33
+ onMessage?: (message: {
34
+ role: string;
35
+ content: string;
36
+ }) => void;
37
+ /** Callback when chat opens/closes */
38
+ onToggle?: (isOpen: boolean) => void;
39
+ }
40
+ declare function MenuIAChat({ widgetId, agentId, apiUrl, primaryColor, position, bubbleSize, bubbleMargin, defaultOpen, inline, metadata, customFields, onMessage, onToggle, }: MenuIAChatProps): react_jsx_runtime.JSX.Element | null;
41
+
42
+ export { MenuIAChat, type MenuIAChatProps };
package/dist/index.js ADDED
@@ -0,0 +1,254 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+
20
+ // src/index.ts
21
+ var index_exports = {};
22
+ __export(index_exports, {
23
+ MenuIAChat: () => MenuIAChat,
24
+ MenuIAClient: () => import_core.MenuIAClient
25
+ });
26
+ module.exports = __toCommonJS(index_exports);
27
+
28
+ // src/MenuIAChat.tsx
29
+ var import_react = require("react");
30
+ var import_react_native = require("react-native");
31
+ var import_jsx_runtime = require("react/jsx-runtime");
32
+ var WebView;
33
+ try {
34
+ WebView = require("react-native-webview").default;
35
+ } catch {
36
+ }
37
+ function MenuIAChat({
38
+ widgetId,
39
+ agentId,
40
+ apiUrl = "https://ia.menuia.com",
41
+ primaryColor = "#7c3aed",
42
+ position = "bottom-right",
43
+ bubbleSize = 56,
44
+ bubbleMargin = 20,
45
+ defaultOpen = false,
46
+ inline = false,
47
+ metadata,
48
+ customFields,
49
+ onMessage,
50
+ onToggle
51
+ }) {
52
+ const [isOpen, setIsOpen] = (0, import_react.useState)(defaultOpen);
53
+ const [unreadCount, setUnreadCount] = (0, import_react.useState)(0);
54
+ const webViewRef = (0, import_react.useRef)(null);
55
+ const id = widgetId || agentId || "";
56
+ const buildUrl = (0, import_react.useCallback)(() => {
57
+ const params = new URLSearchParams();
58
+ params.set("widget", "true");
59
+ if (primaryColor) params.set("color", primaryColor);
60
+ if (metadata?.name) params.set("name", metadata.name);
61
+ if (metadata?.email) params.set("email", metadata.email);
62
+ if (metadata?.phone) params.set("phone", metadata.phone);
63
+ if (customFields) {
64
+ Object.entries(customFields).forEach(([k, v]) => {
65
+ params.set(`cf_${k}`, v);
66
+ });
67
+ }
68
+ return `${apiUrl}/embed/chat/${id}?${params.toString()}`;
69
+ }, [id, apiUrl, primaryColor, metadata, customFields]);
70
+ const toggle = (0, import_react.useCallback)(() => {
71
+ const newState = !isOpen;
72
+ setIsOpen(newState);
73
+ if (newState) setUnreadCount(0);
74
+ onToggle?.(newState);
75
+ }, [isOpen, onToggle]);
76
+ const handleMessage = (0, import_react.useCallback)((event) => {
77
+ try {
78
+ const data = JSON.parse(event.nativeEvent.data);
79
+ if (data.type === "widget:close") {
80
+ setIsOpen(false);
81
+ onToggle?.(false);
82
+ } else if (data.type === "widget:message") {
83
+ if (!isOpen) {
84
+ setUnreadCount((prev) => prev + 1);
85
+ }
86
+ onMessage?.(data.data);
87
+ }
88
+ } catch {
89
+ }
90
+ }, [isOpen, onMessage, onToggle]);
91
+ const injectedJS = `
92
+ (function() {
93
+ window.addEventListener('message', function(e) {
94
+ if (e.data && typeof e.data === 'object') {
95
+ window.ReactNativeWebView.postMessage(JSON.stringify(e.data));
96
+ }
97
+ });
98
+ })();
99
+ true;
100
+ `;
101
+ if (!WebView) {
102
+ return null;
103
+ }
104
+ if (inline) {
105
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react_native.View, { style: styles.inlineContainer, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
106
+ WebView,
107
+ {
108
+ ref: webViewRef,
109
+ source: { uri: buildUrl() },
110
+ style: styles.webview,
111
+ javaScriptEnabled: true,
112
+ domStorageEnabled: true,
113
+ allowsInlineMediaPlayback: true,
114
+ mediaPlaybackRequiresUserAction: false,
115
+ injectedJavaScript: injectedJS,
116
+ onMessage: handleMessage,
117
+ startInLoadingState: true,
118
+ allowsFullscreenVideo: true
119
+ }
120
+ ) });
121
+ }
122
+ const isLeft = position === "bottom-left";
123
+ const { width: screenWidth } = import_react_native.Dimensions.get("window");
124
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [
125
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
126
+ import_react_native.TouchableOpacity,
127
+ {
128
+ onPress: toggle,
129
+ activeOpacity: 0.8,
130
+ style: [
131
+ styles.bubble,
132
+ {
133
+ width: bubbleSize,
134
+ height: bubbleSize,
135
+ borderRadius: bubbleSize / 2,
136
+ backgroundColor: primaryColor,
137
+ bottom: bubbleMargin,
138
+ ...isLeft ? { left: bubbleMargin } : { right: bubbleMargin }
139
+ }
140
+ ],
141
+ children: [
142
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react_native.View, { style: styles.bubbleIcon, children: isOpen ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(CloseIcon, { size: 24 }) : /* @__PURE__ */ (0, import_jsx_runtime.jsx)(ChatIcon, { size: 24 }) }),
143
+ unreadCount > 0 && !isOpen && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react_native.View, { style: styles.badge, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react_native.View, { style: styles.badgeInner, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(BadgeText, { count: unreadCount }) }) })
144
+ ]
145
+ }
146
+ ),
147
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
148
+ import_react_native.Modal,
149
+ {
150
+ visible: isOpen,
151
+ animationType: "slide",
152
+ transparent: false,
153
+ onRequestClose: toggle,
154
+ statusBarTranslucent: true,
155
+ children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_react_native.SafeAreaView, { style: [styles.modalContainer, { backgroundColor: "#0a0a14" }], children: [
156
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react_native.StatusBar, { barStyle: "light-content", backgroundColor: "#0a0a14" }),
157
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
158
+ WebView,
159
+ {
160
+ ref: webViewRef,
161
+ source: { uri: buildUrl() },
162
+ style: styles.webview,
163
+ javaScriptEnabled: true,
164
+ domStorageEnabled: true,
165
+ allowsInlineMediaPlayback: true,
166
+ mediaPlaybackRequiresUserAction: false,
167
+ injectedJavaScript: injectedJS,
168
+ onMessage: handleMessage,
169
+ startInLoadingState: true,
170
+ allowsFullscreenVideo: true,
171
+ allowsBackForwardNavigationGestures: false
172
+ }
173
+ )
174
+ ] })
175
+ }
176
+ )
177
+ ] });
178
+ }
179
+ function ChatIcon({ size }) {
180
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_react_native.View, { style: { width: size, height: size, alignItems: "center", justifyContent: "center" }, children: [
181
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react_native.View, { style: { width: size * 0.7, height: size * 0.55, borderRadius: size * 0.12, borderWidth: 2, borderColor: "white" } }),
182
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react_native.View, { style: { width: 0, height: 0, borderLeftWidth: size * 0.12, borderRightWidth: size * 0.12, borderTopWidth: size * 0.12, borderLeftColor: "transparent", borderRightColor: "transparent", borderTopColor: "white", position: "absolute", bottom: size * 0.08, left: size * 0.15 } })
183
+ ] });
184
+ }
185
+ function CloseIcon({ size }) {
186
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_react_native.View, { style: { width: size, height: size, alignItems: "center", justifyContent: "center" }, children: [
187
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react_native.View, { style: { width: size * 0.6, height: 2.5, backgroundColor: "white", transform: [{ rotate: "45deg" }], position: "absolute" } }),
188
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react_native.View, { style: { width: size * 0.6, height: 2.5, backgroundColor: "white", transform: [{ rotate: "-45deg" }], position: "absolute" } })
189
+ ] });
190
+ }
191
+ function BadgeText({ count }) {
192
+ const React2 = require("react");
193
+ const { Text } = require("react-native");
194
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Text, { style: { color: "white", fontSize: 11, fontWeight: "700" }, children: count > 9 ? "9+" : count });
195
+ }
196
+ var styles = import_react_native.StyleSheet.create({
197
+ inlineContainer: {
198
+ flex: 1,
199
+ overflow: "hidden"
200
+ },
201
+ webview: {
202
+ flex: 1,
203
+ backgroundColor: "#0a0a14"
204
+ },
205
+ bubble: {
206
+ position: "absolute",
207
+ zIndex: 9999,
208
+ elevation: 8,
209
+ alignItems: "center",
210
+ justifyContent: "center",
211
+ ...import_react_native.Platform.select({
212
+ ios: {
213
+ shadowColor: "#000",
214
+ shadowOffset: { width: 0, height: 4 },
215
+ shadowOpacity: 0.3,
216
+ shadowRadius: 8
217
+ },
218
+ android: {
219
+ elevation: 8
220
+ }
221
+ })
222
+ },
223
+ bubbleIcon: {
224
+ alignItems: "center",
225
+ justifyContent: "center"
226
+ },
227
+ badge: {
228
+ position: "absolute",
229
+ top: -4,
230
+ right: -4,
231
+ minWidth: 20,
232
+ height: 20,
233
+ borderRadius: 10,
234
+ backgroundColor: "#ef4444",
235
+ alignItems: "center",
236
+ justifyContent: "center",
237
+ paddingHorizontal: 4
238
+ },
239
+ badgeInner: {
240
+ alignItems: "center",
241
+ justifyContent: "center"
242
+ },
243
+ modalContainer: {
244
+ flex: 1
245
+ }
246
+ });
247
+
248
+ // src/index.ts
249
+ var import_core = require("@menuia/core");
250
+ // Annotate the CommonJS export names for ESM import in node:
251
+ 0 && (module.exports = {
252
+ MenuIAChat,
253
+ MenuIAClient
254
+ });
package/dist/index.mjs ADDED
@@ -0,0 +1,242 @@
1
+ var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, {
2
+ get: (a, b) => (typeof require !== "undefined" ? require : a)[b]
3
+ }) : x)(function(x) {
4
+ if (typeof require !== "undefined") return require.apply(this, arguments);
5
+ throw Error('Dynamic require of "' + x + '" is not supported');
6
+ });
7
+
8
+ // src/MenuIAChat.tsx
9
+ import { useState, useRef, useCallback } from "react";
10
+ import {
11
+ View,
12
+ Modal,
13
+ TouchableOpacity,
14
+ StyleSheet,
15
+ Dimensions,
16
+ Platform,
17
+ SafeAreaView,
18
+ StatusBar
19
+ } from "react-native";
20
+ import { Fragment, jsx, jsxs } from "react/jsx-runtime";
21
+ var WebView;
22
+ try {
23
+ WebView = __require("react-native-webview").default;
24
+ } catch {
25
+ }
26
+ function MenuIAChat({
27
+ widgetId,
28
+ agentId,
29
+ apiUrl = "https://ia.menuia.com",
30
+ primaryColor = "#7c3aed",
31
+ position = "bottom-right",
32
+ bubbleSize = 56,
33
+ bubbleMargin = 20,
34
+ defaultOpen = false,
35
+ inline = false,
36
+ metadata,
37
+ customFields,
38
+ onMessage,
39
+ onToggle
40
+ }) {
41
+ const [isOpen, setIsOpen] = useState(defaultOpen);
42
+ const [unreadCount, setUnreadCount] = useState(0);
43
+ const webViewRef = useRef(null);
44
+ const id = widgetId || agentId || "";
45
+ const buildUrl = useCallback(() => {
46
+ const params = new URLSearchParams();
47
+ params.set("widget", "true");
48
+ if (primaryColor) params.set("color", primaryColor);
49
+ if (metadata?.name) params.set("name", metadata.name);
50
+ if (metadata?.email) params.set("email", metadata.email);
51
+ if (metadata?.phone) params.set("phone", metadata.phone);
52
+ if (customFields) {
53
+ Object.entries(customFields).forEach(([k, v]) => {
54
+ params.set(`cf_${k}`, v);
55
+ });
56
+ }
57
+ return `${apiUrl}/embed/chat/${id}?${params.toString()}`;
58
+ }, [id, apiUrl, primaryColor, metadata, customFields]);
59
+ const toggle = useCallback(() => {
60
+ const newState = !isOpen;
61
+ setIsOpen(newState);
62
+ if (newState) setUnreadCount(0);
63
+ onToggle?.(newState);
64
+ }, [isOpen, onToggle]);
65
+ const handleMessage = useCallback((event) => {
66
+ try {
67
+ const data = JSON.parse(event.nativeEvent.data);
68
+ if (data.type === "widget:close") {
69
+ setIsOpen(false);
70
+ onToggle?.(false);
71
+ } else if (data.type === "widget:message") {
72
+ if (!isOpen) {
73
+ setUnreadCount((prev) => prev + 1);
74
+ }
75
+ onMessage?.(data.data);
76
+ }
77
+ } catch {
78
+ }
79
+ }, [isOpen, onMessage, onToggle]);
80
+ const injectedJS = `
81
+ (function() {
82
+ window.addEventListener('message', function(e) {
83
+ if (e.data && typeof e.data === 'object') {
84
+ window.ReactNativeWebView.postMessage(JSON.stringify(e.data));
85
+ }
86
+ });
87
+ })();
88
+ true;
89
+ `;
90
+ if (!WebView) {
91
+ return null;
92
+ }
93
+ if (inline) {
94
+ return /* @__PURE__ */ jsx(View, { style: styles.inlineContainer, children: /* @__PURE__ */ jsx(
95
+ WebView,
96
+ {
97
+ ref: webViewRef,
98
+ source: { uri: buildUrl() },
99
+ style: styles.webview,
100
+ javaScriptEnabled: true,
101
+ domStorageEnabled: true,
102
+ allowsInlineMediaPlayback: true,
103
+ mediaPlaybackRequiresUserAction: false,
104
+ injectedJavaScript: injectedJS,
105
+ onMessage: handleMessage,
106
+ startInLoadingState: true,
107
+ allowsFullscreenVideo: true
108
+ }
109
+ ) });
110
+ }
111
+ const isLeft = position === "bottom-left";
112
+ const { width: screenWidth } = Dimensions.get("window");
113
+ return /* @__PURE__ */ jsxs(Fragment, { children: [
114
+ /* @__PURE__ */ jsxs(
115
+ TouchableOpacity,
116
+ {
117
+ onPress: toggle,
118
+ activeOpacity: 0.8,
119
+ style: [
120
+ styles.bubble,
121
+ {
122
+ width: bubbleSize,
123
+ height: bubbleSize,
124
+ borderRadius: bubbleSize / 2,
125
+ backgroundColor: primaryColor,
126
+ bottom: bubbleMargin,
127
+ ...isLeft ? { left: bubbleMargin } : { right: bubbleMargin }
128
+ }
129
+ ],
130
+ children: [
131
+ /* @__PURE__ */ jsx(View, { style: styles.bubbleIcon, children: isOpen ? /* @__PURE__ */ jsx(CloseIcon, { size: 24 }) : /* @__PURE__ */ jsx(ChatIcon, { size: 24 }) }),
132
+ unreadCount > 0 && !isOpen && /* @__PURE__ */ jsx(View, { style: styles.badge, children: /* @__PURE__ */ jsx(View, { style: styles.badgeInner, children: /* @__PURE__ */ jsx(BadgeText, { count: unreadCount }) }) })
133
+ ]
134
+ }
135
+ ),
136
+ /* @__PURE__ */ jsx(
137
+ Modal,
138
+ {
139
+ visible: isOpen,
140
+ animationType: "slide",
141
+ transparent: false,
142
+ onRequestClose: toggle,
143
+ statusBarTranslucent: true,
144
+ children: /* @__PURE__ */ jsxs(SafeAreaView, { style: [styles.modalContainer, { backgroundColor: "#0a0a14" }], children: [
145
+ /* @__PURE__ */ jsx(StatusBar, { barStyle: "light-content", backgroundColor: "#0a0a14" }),
146
+ /* @__PURE__ */ jsx(
147
+ WebView,
148
+ {
149
+ ref: webViewRef,
150
+ source: { uri: buildUrl() },
151
+ style: styles.webview,
152
+ javaScriptEnabled: true,
153
+ domStorageEnabled: true,
154
+ allowsInlineMediaPlayback: true,
155
+ mediaPlaybackRequiresUserAction: false,
156
+ injectedJavaScript: injectedJS,
157
+ onMessage: handleMessage,
158
+ startInLoadingState: true,
159
+ allowsFullscreenVideo: true,
160
+ allowsBackForwardNavigationGestures: false
161
+ }
162
+ )
163
+ ] })
164
+ }
165
+ )
166
+ ] });
167
+ }
168
+ function ChatIcon({ size }) {
169
+ return /* @__PURE__ */ jsxs(View, { style: { width: size, height: size, alignItems: "center", justifyContent: "center" }, children: [
170
+ /* @__PURE__ */ jsx(View, { style: { width: size * 0.7, height: size * 0.55, borderRadius: size * 0.12, borderWidth: 2, borderColor: "white" } }),
171
+ /* @__PURE__ */ jsx(View, { style: { width: 0, height: 0, borderLeftWidth: size * 0.12, borderRightWidth: size * 0.12, borderTopWidth: size * 0.12, borderLeftColor: "transparent", borderRightColor: "transparent", borderTopColor: "white", position: "absolute", bottom: size * 0.08, left: size * 0.15 } })
172
+ ] });
173
+ }
174
+ function CloseIcon({ size }) {
175
+ return /* @__PURE__ */ jsxs(View, { style: { width: size, height: size, alignItems: "center", justifyContent: "center" }, children: [
176
+ /* @__PURE__ */ jsx(View, { style: { width: size * 0.6, height: 2.5, backgroundColor: "white", transform: [{ rotate: "45deg" }], position: "absolute" } }),
177
+ /* @__PURE__ */ jsx(View, { style: { width: size * 0.6, height: 2.5, backgroundColor: "white", transform: [{ rotate: "-45deg" }], position: "absolute" } })
178
+ ] });
179
+ }
180
+ function BadgeText({ count }) {
181
+ const React2 = __require("react");
182
+ const { Text } = __require("react-native");
183
+ return /* @__PURE__ */ jsx(Text, { style: { color: "white", fontSize: 11, fontWeight: "700" }, children: count > 9 ? "9+" : count });
184
+ }
185
+ var styles = StyleSheet.create({
186
+ inlineContainer: {
187
+ flex: 1,
188
+ overflow: "hidden"
189
+ },
190
+ webview: {
191
+ flex: 1,
192
+ backgroundColor: "#0a0a14"
193
+ },
194
+ bubble: {
195
+ position: "absolute",
196
+ zIndex: 9999,
197
+ elevation: 8,
198
+ alignItems: "center",
199
+ justifyContent: "center",
200
+ ...Platform.select({
201
+ ios: {
202
+ shadowColor: "#000",
203
+ shadowOffset: { width: 0, height: 4 },
204
+ shadowOpacity: 0.3,
205
+ shadowRadius: 8
206
+ },
207
+ android: {
208
+ elevation: 8
209
+ }
210
+ })
211
+ },
212
+ bubbleIcon: {
213
+ alignItems: "center",
214
+ justifyContent: "center"
215
+ },
216
+ badge: {
217
+ position: "absolute",
218
+ top: -4,
219
+ right: -4,
220
+ minWidth: 20,
221
+ height: 20,
222
+ borderRadius: 10,
223
+ backgroundColor: "#ef4444",
224
+ alignItems: "center",
225
+ justifyContent: "center",
226
+ paddingHorizontal: 4
227
+ },
228
+ badgeInner: {
229
+ alignItems: "center",
230
+ justifyContent: "center"
231
+ },
232
+ modalContainer: {
233
+ flex: 1
234
+ }
235
+ });
236
+
237
+ // src/index.ts
238
+ import { MenuIAClient } from "@menuia/core";
239
+ export {
240
+ MenuIAChat,
241
+ MenuIAClient
242
+ };
package/package.json ADDED
@@ -0,0 +1,28 @@
1
+ {
2
+ "name": "@menuia/react-native",
3
+ "version": "1.0.0",
4
+ "description": "MenuIA Chat SDK - React Native Component",
5
+ "main": "dist/index.js",
6
+ "module": "dist/index.mjs",
7
+ "types": "dist/index.d.ts",
8
+ "files": ["dist"],
9
+ "scripts": {
10
+ "build": "tsup src/index.ts --format cjs,esm --dts --clean --external react --external react-native --external react-native-webview --external @menuia/core",
11
+ "dev": "tsup src/index.ts --format cjs,esm --dts --watch --external react --external react-native --external react-native-webview --external @menuia/core"
12
+ },
13
+ "peerDependencies": {
14
+ "react": ">=17.0.0",
15
+ "react-native": ">=0.60.0",
16
+ "react-native-webview": ">=11.0.0"
17
+ },
18
+ "dependencies": {
19
+ "@menuia/core": "^1.1.0"
20
+ },
21
+ "devDependencies": {
22
+ "@types/react": "^18.2.0",
23
+ "react": "^18.2.0",
24
+ "tsup": "^8.0.0",
25
+ "typescript": "^5.3.0"
26
+ },
27
+ "license": "MIT"
28
+ }