react-native-tpstreams 1.1.3 → 1.1.4-dev.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.
Files changed (46) hide show
  1. package/android/app/build/generated/source/codegen/java/com/facebook/react/viewmanagers/TPStreamsRNPlayerViewManagerDelegate.java +87 -0
  2. package/android/app/build/generated/source/codegen/java/com/facebook/react/viewmanagers/TPStreamsRNPlayerViewManagerInterface.java +34 -0
  3. package/android/app/build/generated/source/codegen/jni/CMakeLists.txt +36 -0
  4. package/android/app/build/generated/source/codegen/jni/TPStreamsPlayerViewSpec-generated.cpp +22 -0
  5. package/android/app/build/generated/source/codegen/jni/TPStreamsPlayerViewSpec.h +24 -0
  6. package/android/app/build/generated/source/codegen/jni/react/renderer/components/TPStreamsPlayerViewSpec/ComponentDescriptors.cpp +22 -0
  7. package/android/app/build/generated/source/codegen/jni/react/renderer/components/TPStreamsPlayerViewSpec/ComponentDescriptors.h +24 -0
  8. package/android/app/build/generated/source/codegen/jni/react/renderer/components/TPStreamsPlayerViewSpec/EventEmitters.cpp +107 -0
  9. package/android/app/build/generated/source/codegen/jni/react/renderer/components/TPStreamsPlayerViewSpec/EventEmitters.h +81 -0
  10. package/android/app/build/generated/source/codegen/jni/react/renderer/components/TPStreamsPlayerViewSpec/Props.cpp +32 -0
  11. package/android/app/build/generated/source/codegen/jni/react/renderer/components/TPStreamsPlayerViewSpec/Props.h +34 -0
  12. package/android/app/build/generated/source/codegen/jni/react/renderer/components/TPStreamsPlayerViewSpec/ShadowNodes.cpp +17 -0
  13. package/android/app/build/generated/source/codegen/jni/react/renderer/components/TPStreamsPlayerViewSpec/ShadowNodes.h +32 -0
  14. package/android/app/build/generated/source/codegen/jni/react/renderer/components/TPStreamsPlayerViewSpec/States.cpp +16 -0
  15. package/android/app/build/generated/source/codegen/jni/react/renderer/components/TPStreamsPlayerViewSpec/States.h +29 -0
  16. package/android/app/build/generated/source/codegen/jni/react/renderer/components/TPStreamsPlayerViewSpec/TPStreamsPlayerViewSpecJSI-generated.cpp +17 -0
  17. package/android/app/build/generated/source/codegen/jni/react/renderer/components/TPStreamsPlayerViewSpec/TPStreamsPlayerViewSpecJSI.h +19 -0
  18. package/android/gradle.properties +1 -1
  19. package/lib/module/TPStreamsLiveChat.js +133 -0
  20. package/lib/module/TPStreamsLiveChat.js.map +1 -0
  21. package/lib/module/index.js +1 -0
  22. package/lib/module/index.js.map +1 -1
  23. package/lib/module/types/TPStreamsLiveChatTypes.js +29 -0
  24. package/lib/module/types/TPStreamsLiveChatTypes.js.map +1 -0
  25. package/lib/module/utils/constants.js +28 -0
  26. package/lib/module/utils/constants.js.map +1 -0
  27. package/lib/module/utils/liveChatHtmlGenerator.js +131 -0
  28. package/lib/module/utils/liveChatHtmlGenerator.js.map +1 -0
  29. package/lib/typescript/src/TPStreamsLiveChat.d.ts +5 -0
  30. package/lib/typescript/src/TPStreamsLiveChat.d.ts.map +1 -0
  31. package/lib/typescript/src/TPStreamsPlayerViewNativeComponent.d.ts +1 -0
  32. package/lib/typescript/src/TPStreamsPlayerViewNativeComponent.d.ts.map +1 -1
  33. package/lib/typescript/src/index.d.ts +2 -0
  34. package/lib/typescript/src/index.d.ts.map +1 -1
  35. package/lib/typescript/src/types/TPStreamsLiveChatTypes.d.ts +77 -0
  36. package/lib/typescript/src/types/TPStreamsLiveChatTypes.d.ts.map +1 -0
  37. package/lib/typescript/src/utils/constants.d.ts +20 -0
  38. package/lib/typescript/src/utils/constants.d.ts.map +1 -0
  39. package/lib/typescript/src/utils/liveChatHtmlGenerator.d.ts +6 -0
  40. package/lib/typescript/src/utils/liveChatHtmlGenerator.d.ts.map +1 -0
  41. package/package.json +4 -1
  42. package/src/TPStreamsLiveChat.tsx +189 -0
  43. package/src/index.tsx +9 -0
  44. package/src/types/TPStreamsLiveChatTypes.ts +99 -0
  45. package/src/utils/constants.ts +28 -0
  46. package/src/utils/liveChatHtmlGenerator.ts +142 -0
@@ -0,0 +1,189 @@
1
+ import {
2
+ forwardRef,
3
+ useRef,
4
+ useImperativeHandle,
5
+ useState,
6
+ useCallback,
7
+ useMemo,
8
+ } from 'react';
9
+ import {
10
+ View,
11
+ ActivityIndicator,
12
+ StyleSheet,
13
+ type NativeSyntheticEvent,
14
+ } from 'react-native';
15
+ import { WebView, type WebViewMessageEvent } from 'react-native-webview';
16
+
17
+ import type {
18
+ TPStreamsLiveChatProps,
19
+ TPStreamsLiveChatRef,
20
+ } from './types/TPStreamsLiveChatTypes';
21
+ import { isChatMessage } from './types/TPStreamsLiveChatTypes';
22
+ import { generateChatHTML } from './utils/liveChatHtmlGenerator';
23
+ import { CHAT_SDK_CONSTANTS, ChatMessageType } from './utils/constants';
24
+
25
+ const TPStreamsLiveChat = forwardRef<
26
+ TPStreamsLiveChatRef,
27
+ TPStreamsLiveChatProps
28
+ >((props, ref) => {
29
+ const {
30
+ username,
31
+ roomId,
32
+ title,
33
+ colors,
34
+ typography,
35
+ customCSS,
36
+ style,
37
+ onChatReady,
38
+ onChatError,
39
+ onMessageReceived,
40
+ } = props;
41
+
42
+ const webViewRef = useRef<WebView>(null);
43
+ const [status, setStatus] = useState<'loading' | 'ready' | 'error'>(
44
+ 'loading'
45
+ );
46
+
47
+ const htmlContent = useMemo(
48
+ () =>
49
+ generateChatHTML({
50
+ username,
51
+ roomId,
52
+ title,
53
+ colors,
54
+ typography,
55
+ customCSS,
56
+ }),
57
+ [username, roomId, title, colors, typography, customCSS]
58
+ );
59
+
60
+ const handleMessage = useCallback(
61
+ (event: WebViewMessageEvent) => {
62
+ try {
63
+ const { type, message } = JSON.parse(event.nativeEvent.data);
64
+
65
+ switch (type) {
66
+ case ChatMessageType.READY:
67
+ setStatus('ready');
68
+ onChatReady?.();
69
+ break;
70
+
71
+ case ChatMessageType.ERROR:
72
+ setStatus('error');
73
+ onChatError?.(message || 'SDK initialization failed');
74
+ break;
75
+
76
+ case ChatMessageType.MESSAGE:
77
+ if (isChatMessage(message)) {
78
+ onMessageReceived?.(message);
79
+ } else {
80
+ console.warn(
81
+ '[TPStreamsLiveChat] Received invalid message format:',
82
+ message
83
+ );
84
+ }
85
+ break;
86
+
87
+ case ChatMessageType.DEBUG:
88
+ console.debug('[TPStreamsLiveChat] WebView:', message);
89
+ break;
90
+ }
91
+ } catch (err) {
92
+ console.error('[TPStreamsLiveChat] Failed to parse message:', err);
93
+ }
94
+ },
95
+ [onChatReady, onChatError, onMessageReceived]
96
+ );
97
+
98
+ const handleWebViewError = useCallback(
99
+ (syntheticEvent: NativeSyntheticEvent<any>) => {
100
+ const { nativeEvent } = syntheticEvent;
101
+ setStatus('error');
102
+ onChatError?.(nativeEvent.description || 'WebView failed to load');
103
+ },
104
+ [onChatError]
105
+ );
106
+
107
+ useImperativeHandle(
108
+ ref,
109
+ () => ({
110
+ reload: () => {
111
+ setStatus('loading');
112
+ webViewRef.current?.reload();
113
+ },
114
+ injectCSS: (css: string) => {
115
+ const script = `
116
+ (function() {
117
+ const style = document.createElement('style');
118
+ style.textContent = ${JSON.stringify(css)};
119
+ document.head.appendChild(style);
120
+ })();
121
+ `;
122
+ webViewRef.current?.injectJavaScript(script);
123
+ },
124
+ }),
125
+ []
126
+ );
127
+
128
+ const renderLoading = () =>
129
+ status === 'loading' && (
130
+ <View
131
+ style={[
132
+ styles.overlay,
133
+ {
134
+ backgroundColor:
135
+ colors?.background || CHAT_SDK_CONSTANTS.DEFAULT_BACKGROUND_COLOR,
136
+ },
137
+ ]}
138
+ >
139
+ <ActivityIndicator
140
+ size="large"
141
+ color={colors?.primary || CHAT_SDK_CONSTANTS.DEFAULT_PRIMARY_COLOR}
142
+ />
143
+ </View>
144
+ );
145
+
146
+ return (
147
+ <View style={[styles.container, style]}>
148
+ <WebView
149
+ key={`${colors?.background}-${typography?.fontFamily}`}
150
+ ref={webViewRef}
151
+ source={{
152
+ html: htmlContent,
153
+ baseUrl: CHAT_SDK_CONSTANTS.BASE_URL,
154
+ }}
155
+ originWhitelist={[CHAT_SDK_CONSTANTS.BASE_URL]}
156
+ javaScriptEnabled={true}
157
+ domStorageEnabled={true}
158
+ onMessage={handleMessage}
159
+ onError={handleWebViewError}
160
+ style={styles.webview}
161
+ allowsInlineMediaPlayback={true}
162
+ mediaPlaybackRequiresUserAction={false}
163
+ scrollEnabled={false}
164
+ />
165
+ {renderLoading()}
166
+ </View>
167
+ );
168
+ });
169
+
170
+ TPStreamsLiveChat.displayName = 'TPStreamsLiveChat';
171
+
172
+ const styles = StyleSheet.create({
173
+ container: {
174
+ flex: 1,
175
+ overflow: 'hidden',
176
+ },
177
+ webview: {
178
+ flex: 1,
179
+ backgroundColor: 'transparent',
180
+ },
181
+ overlay: {
182
+ ...StyleSheet.absoluteFillObject,
183
+ justifyContent: 'center',
184
+ alignItems: 'center',
185
+ zIndex: 10,
186
+ },
187
+ });
188
+
189
+ export default TPStreamsLiveChat;
package/src/index.tsx CHANGED
@@ -33,3 +33,12 @@ export const TPStreams = {
33
33
  TPStreamsModule.initialize(organizationId);
34
34
  },
35
35
  };
36
+
37
+ export { default as TPStreamsLiveChat } from './TPStreamsLiveChat';
38
+ export type {
39
+ TPStreamsLiveChatProps,
40
+ TPStreamsLiveChatRef,
41
+ ChatColors,
42
+ ChatTypography,
43
+ ChatMessage,
44
+ } from './types/TPStreamsLiveChatTypes';
@@ -0,0 +1,99 @@
1
+ import type { ViewStyle } from 'react-native';
2
+
3
+ /**
4
+ * Color configuration for the chat interface
5
+ */
6
+ export interface ChatColors {
7
+ /** Primary brand color (buttons, links, accents) */
8
+ primary?: string;
9
+ /** Chat background color */
10
+ background?: string;
11
+ /** Default text color */
12
+ text?: string;
13
+ /** Input field background color */
14
+ inputBackground?: string;
15
+ /** Border and divider color */
16
+ border?: string;
17
+ }
18
+
19
+ /**
20
+ * Chat message structure
21
+ */
22
+ export interface ChatMessage {
23
+ id: string;
24
+ username: string;
25
+ message: string;
26
+ timestamp: number;
27
+ }
28
+
29
+ /**
30
+ * Type guard for ChatMessage
31
+ */
32
+ export function isChatMessage(data: any): data is ChatMessage {
33
+ return (
34
+ data &&
35
+ typeof data.id === 'string' &&
36
+ typeof data.username === 'string' &&
37
+ typeof data.message === 'string' &&
38
+ typeof data.timestamp === 'number'
39
+ );
40
+ }
41
+
42
+ /**
43
+ * Typography configuration for the chat interface
44
+ */
45
+ export interface ChatTypography {
46
+ /** Base font size in pixels */
47
+ fontSize?: number;
48
+ /** Font family (e.g., 'Inter, sans-serif') */
49
+ fontFamily?: string;
50
+ /** Font weight (e.g., '400', 'bold', 600) */
51
+ fontWeight?: string | number;
52
+ /** Line height multiplier */
53
+ lineHeight?: number;
54
+ }
55
+
56
+ /**
57
+ * Props for TPStreamsLiveChat component
58
+ */
59
+ export interface TPStreamsLiveChatProps {
60
+ // Required configuration
61
+ /** Username of the current user */
62
+ username: string;
63
+ /** Room ID for the chat (obtained from live stream details) */
64
+ roomId: string;
65
+ /** Title displayed in the chat header */
66
+ title: string;
67
+
68
+ // Optional styling configuration
69
+ /** Color scheme configuration */
70
+ colors?: ChatColors;
71
+ /** Typography configuration */
72
+ typography?: ChatTypography;
73
+
74
+ // Advanced customization
75
+ /** Custom CSS to inject (for advanced users) */
76
+ customCSS?: string;
77
+
78
+ // Standard React Native props
79
+ /** Container style */
80
+ style?: ViewStyle;
81
+
82
+ // Event callbacks
83
+ /** Called when chat is successfully loaded and ready */
84
+ onChatReady?: () => void;
85
+ /** Called when an error occurs */
86
+ onChatError?: (error: string) => void;
87
+ /** Called when a new message is received */
88
+ onMessageReceived?: (message: ChatMessage) => void;
89
+ }
90
+
91
+ /**
92
+ * Ref methods exposed by TPStreamsLiveChat component
93
+ */
94
+ export interface TPStreamsLiveChatRef {
95
+ /** Reload the chat interface */
96
+ reload: () => void;
97
+ /** Inject custom CSS dynamically */
98
+ injectCSS?: (css: string) => void;
99
+ }
@@ -0,0 +1,28 @@
1
+ /**
2
+ * URLs for the Live Chat SDK assets and base configuration
3
+ */
4
+ export const CHAT_SDK_CONSTANTS = {
5
+ // The domain where the chat is hosted/associated
6
+ BASE_URL: 'https://media.testpress.in',
7
+
8
+ // CDN path for the CSS styles
9
+ STYLES_URL: 'https://media.testpress.in/static/live_chat/live_chat.css',
10
+
11
+ // CDN path for the UMD build of the SDK
12
+ SDK_SCRIPT_URL:
13
+ 'https://media.testpress.in/static/live_chat/live_chat.umd.cjs',
14
+
15
+ // Default values
16
+ DEFAULT_PRIMARY_COLOR: '#007AFF',
17
+ DEFAULT_BACKGROUND_COLOR: '#FFFFFF',
18
+ };
19
+
20
+ /**
21
+ * Message types for communication between WebView and React Native
22
+ */
23
+ export enum ChatMessageType {
24
+ READY = 'ready',
25
+ ERROR = 'error',
26
+ MESSAGE = 'message',
27
+ DEBUG = 'debug',
28
+ }
@@ -0,0 +1,142 @@
1
+ import type {
2
+ TPStreamsLiveChatProps,
3
+ ChatColors,
4
+ ChatTypography,
5
+ } from '../types/TPStreamsLiveChatTypes';
6
+ import { CHAT_SDK_CONSTANTS, ChatMessageType } from './constants';
7
+
8
+ /**
9
+ * Generates the complete HTML content for the chat WebView
10
+ */
11
+ export function generateChatHTML(props: TPStreamsLiveChatProps): string {
12
+ const { username, roomId, title } = props;
13
+ const styles = generateStylesAndScripts(props);
14
+
15
+ return `
16
+ <!DOCTYPE html>
17
+ <html lang="en" style="height: 100%; margin: 0;">
18
+ <head>
19
+ <meta charset="UTF-8">
20
+ <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no">
21
+ <link rel="stylesheet" href="${CHAT_SDK_CONSTANTS.STYLES_URL}">
22
+ ${styles.css}
23
+ </head>
24
+ <body style="height: 100%; margin: 0; overflow: hidden;">
25
+ <div id="app" style="height: 100%;"></div>
26
+ <script src="${CHAT_SDK_CONSTANTS.SDK_SCRIPT_URL}"></script>
27
+ <script>
28
+ (function() {
29
+ const config = {
30
+ username: ${JSON.stringify(username)},
31
+ roomId: ${JSON.stringify(roomId)},
32
+ title: ${JSON.stringify(title)}
33
+ };
34
+
35
+ function postToNative(type, message = null) {
36
+ if (window.ReactNativeWebView) {
37
+ window.ReactNativeWebView.postMessage(JSON.stringify({ type, message }));
38
+ }
39
+ }
40
+
41
+ try {
42
+ new TPStreamsChat.load(document.querySelector("#app"), config);
43
+ postToNative('${ChatMessageType.READY}');
44
+ } catch (error) {
45
+ postToNative('${ChatMessageType.ERROR}', error.message || 'Failed to initialize chat');
46
+ }
47
+ })();
48
+ </script>
49
+ </body>
50
+ </html>
51
+ `;
52
+ }
53
+
54
+ /**
55
+ * Combines all CSS generation logic
56
+ */
57
+ function generateStylesAndScripts(props: TPStreamsLiveChatProps) {
58
+ const { colors, typography, customCSS } = props;
59
+ const rules: string[] = [];
60
+
61
+ if (typography) rules.push(getTypographyCSS(typography));
62
+ if (colors) rules.push(getColorCSS(colors));
63
+ if (customCSS) rules.push(customCSS);
64
+
65
+ return {
66
+ css: `<style>${rules.join('\n\n')}</style>`,
67
+ };
68
+ }
69
+
70
+ /**
71
+ * Generate color-related CSS using functional approach
72
+ */
73
+ function getColorCSS(colors: ChatColors): string {
74
+ const rules: string[] = [];
75
+
76
+ if (colors.primary) {
77
+ rules.push(`
78
+ button, [class*="bg-blue-"], [class*="bg-indigo-"], [class*="primary"] {
79
+ background-color: ${colors.primary} !important;
80
+ color: white !important;
81
+ }
82
+ .text-blue-600, .text-indigo-600, [class*="text-blue-"]:not([class*="bg-"]), [class*="text-indigo-"]:not([class*="bg-"]) {
83
+ color: ${colors.primary} !important;
84
+ }
85
+ [class*="bg-blue-"] *, [class*="bg-indigo-"] *, [class*="primary"] * {
86
+ color: white !important;
87
+ }
88
+ `);
89
+ }
90
+
91
+ if (colors.background) {
92
+ rules.push(`
93
+ body, #app, .chat-container, [class*="bg-white"], [class*="bg-gray-50"], [class*="bg-slate-"] {
94
+ background-color: ${colors.background} !important;
95
+ }
96
+ `);
97
+ }
98
+
99
+ if (colors.text) {
100
+ rules.push(`
101
+ body, p, input, textarea,
102
+ div:not([class*="bg-blue-"]):not([class*="bg-indigo-"]):not([class*="primary"]),
103
+ span:not([class*="bg-blue-"]):not([class*="bg-indigo-"]):not([class*="primary"]) {
104
+ color: ${colors.text} !important;
105
+ }
106
+ `);
107
+ }
108
+
109
+ if (colors.inputBackground) {
110
+ rules.push(`
111
+ textarea, input[type="text"], [class*="bg-gray-"], [class*="bg-slate-"] {
112
+ background-color: ${colors.inputBackground} !important;
113
+ }
114
+ `);
115
+ }
116
+
117
+ if (colors.border) {
118
+ rules.push(`
119
+ [class*="border"], [class*="divide-"] > * {
120
+ border-color: ${colors.border} !important;
121
+ }
122
+ `);
123
+ }
124
+
125
+ return rules.join('\n');
126
+ }
127
+
128
+ function getTypographyCSS(typography: ChatTypography): string {
129
+ const styles: string[] = [];
130
+ if (typography.fontSize)
131
+ styles.push(`font-size: ${typography.fontSize}px !important;`);
132
+ if (typography.fontFamily)
133
+ styles.push(`font-family: ${typography.fontFamily} !important;`);
134
+ if (typography.fontWeight)
135
+ styles.push(`font-weight: ${typography.fontWeight} !important;`);
136
+ if (typography.lineHeight)
137
+ styles.push(`line-height: ${typography.lineHeight} !important;`);
138
+
139
+ return styles.length > 0
140
+ ? `body, button, input, textarea, div, span, p { ${styles.join(' ')} }`
141
+ : '';
142
+ }