@vanira/sdk-react-native 0.0.2
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 +239 -0
- package/package.json +53 -0
- package/src/__tests__/WebRTCClient.integration.test.ts +396 -0
- package/src/__tests__/adapters.test.ts +475 -0
- package/src/__tests__/httpResponse.test.ts +25 -0
- package/src/__tests__/mocks/react-native-incall-manager.ts +8 -0
- package/src/__tests__/mocks/react-native-permissions.ts +15 -0
- package/src/__tests__/mocks/react-native-webrtc.ts +6 -0
- package/src/__tests__/mocks/react-native.ts +28 -0
- package/src/__tests__/preset.test.ts +239 -0
- package/src/__tests__/resolveRuntimeConfig.test.ts +90 -0
- package/src/__tests__/storage.test.ts +211 -0
- package/src/__tests__/webrtcSignaling.test.ts +42 -0
- package/src/adapters/PeerConnectionAdapter.ts +101 -0
- package/src/adapters/browser/BrowserAudioAdapter.ts +43 -0
- package/src/adapters/browser/BrowserDataChannelAdapter.ts +69 -0
- package/src/adapters/browser/BrowserMediaAdapter.ts +15 -0
- package/src/adapters/browser/BrowserPeerAdapter.ts +14 -0
- package/src/adapters/browser/index.ts +4 -0
- package/src/adapters/interfaces.ts +84 -0
- package/src/adapters/react-native/RNAudioAdapter.ts +42 -0
- package/src/adapters/react-native/RNDataChannelAdapter.ts +79 -0
- package/src/adapters/react-native/RNMediaAdapter.ts +46 -0
- package/src/adapters/react-native/RNPeerAdapter.ts +28 -0
- package/src/adapters/react-native/callAudioRouting.ts +115 -0
- package/src/adapters/react-native/decodeUtf8.ts +72 -0
- package/src/adapters/react-native/index.ts +4 -0
- package/src/adapters/react-native/rnUploadFile.ts +76 -0
- package/src/adapters/storage/BrowserDualStorageAdapter.ts +71 -0
- package/src/adapters/storage/MemoryStorageAdapter.ts +50 -0
- package/src/adapters/storage/StorageAdapter.ts +21 -0
- package/src/adapters/storage/createSyncStorageAdapter.ts +40 -0
- package/src/adapters/storage/index.ts +7 -0
- package/src/api/services/ChatService.ts +304 -0
- package/src/api/services/ConfigService.ts +33 -0
- package/src/assets/icons.js +35 -0
- package/src/cdn.ts +68 -0
- package/src/core/CallSessionStore.ts +137 -0
- package/src/core/DraggableController.ts +83 -0
- package/src/core/SessionManager.ts +322 -0
- package/src/core/VaniraAI.ts +464 -0
- package/src/core/WebRTCClient.ts +1012 -0
- package/src/core/httpResponse.ts +22 -0
- package/src/core/iceServers.ts +18 -0
- package/src/core/toolCallNormalize.ts +80 -0
- package/src/core/voice-client.js +236 -0
- package/src/core/webrtcSignaling.ts +72 -0
- package/src/index.js +34 -0
- package/src/index.ts +6 -0
- package/src/platforms/browser.ts +67 -0
- package/src/platforms/react-native.ts +105 -0
- package/src/presets/BookingCalendarModal.tsx +457 -0
- package/src/presets/CameraModal.tsx +576 -0
- package/src/presets/DynamicFormModal.tsx +378 -0
- package/src/presets/NativePresetRenderer.tsx +350 -0
- package/src/presets/NavigateHandler.tsx +75 -0
- package/src/presets/PresetHost.tsx +155 -0
- package/src/presets/PresetShellModal.tsx +97 -0
- package/src/presets/UploadModal.tsx +321 -0
- package/src/presets/calendar/calendarUtils.ts +386 -0
- package/src/presets/call/CallSpeakerToggle.tsx +59 -0
- package/src/presets/call/callAudioRouting.ts +2 -0
- package/src/presets/call/useCallSpeaker.ts +31 -0
- package/src/presets/camera/cameraPermissions.ts +18 -0
- package/src/presets/camera/cameraStream.ts +19 -0
- package/src/presets/camera/cameraUtils.ts +21 -0
- package/src/presets/camera/useLivenessFlow.ts +95 -0
- package/src/presets/chalkboard/ChalkboardOverlay.tsx +156 -0
- package/src/presets/chalkboard/EraseTextHandler.tsx +95 -0
- package/src/presets/chalkboard/TypeTextHandler.tsx +107 -0
- package/src/presets/chalkboard/boardAbort.ts +36 -0
- package/src/presets/chalkboard/boardQueue.ts +620 -0
- package/src/presets/chalkboard/chalkboardSession.ts +75 -0
- package/src/presets/chalkboard/drawUtils.ts +123 -0
- package/src/presets/chalkboard/textUtils.ts +109 -0
- package/src/presets/clipRegion/ClipRegionModal.tsx +261 -0
- package/src/presets/clipRegion/clipRegionBridge.ts +19 -0
- package/src/presets/form/formValidation.ts +104 -0
- package/src/presets/form/parseFormFields.ts +171 -0
- package/src/presets/host/HostElementPresetHandler.tsx +155 -0
- package/src/presets/host/hostPresetBridge.ts +71 -0
- package/src/presets/index.ts +63 -0
- package/src/presets/liveScreen/CloseLiveScreenHandler.tsx +36 -0
- package/src/presets/liveScreen/LiveScreenCaptureHost.tsx +312 -0
- package/src/presets/liveScreen/LiveScreenHandler.tsx +25 -0
- package/src/presets/liveScreen/LiveScreenPipOverlay.tsx +6 -0
- package/src/presets/liveScreen/liveScreenSession.ts +73 -0
- package/src/presets/liveVision/CloseLiveVisionHandler.tsx +29 -0
- package/src/presets/liveVision/LiveVisionCameraHost.tsx +317 -0
- package/src/presets/liveVision/LiveVisionHandler.tsx +26 -0
- package/src/presets/liveVision/LiveVisionPipOverlay.tsx +7 -0
- package/src/presets/liveVision/liveVisionFrameLoop.ts +38 -0
- package/src/presets/liveVision/liveVisionSession.ts +75 -0
- package/src/presets/liveVision/liveVisionUpload.ts +62 -0
- package/src/presets/navigation/internalRouteRegistry.ts +25 -0
- package/src/presets/navigation/navigationBridge.ts +76 -0
- package/src/presets/navigation/navigationTypes.ts +12 -0
- package/src/presets/parseToolCall.ts +60 -0
- package/src/presets/presetClientAdapter.ts +29 -0
- package/src/presets/presetCompletion.ts +91 -0
- package/src/presets/presetEventHelpers.ts +45 -0
- package/src/presets/registry.ts +128 -0
- package/src/presets/streaming/mediaFrameUpload.ts +93 -0
- package/src/presets/types.ts +74 -0
- package/src/presets/upload/pickUploadFile.ts +256 -0
- package/src/presets/upload/uploadFormats.ts +163 -0
- package/src/presets/upload/uploadUtils.ts +68 -0
- package/src/react/PresetRenderer.tsx +144 -0
- package/src/react/index.ts +1 -0
- package/src/runtime/browserRuntime.ts +54 -0
- package/src/runtime/platform.ts +17 -0
- package/src/runtime/reactNativeRuntime.ts +68 -0
- package/src/runtime/resolveRuntimeConfig.ts +75 -0
- package/src/runtime/runtimeBundles.ts +74 -0
- package/src/runtime/types.ts +135 -0
- package/src/types/react-native-incall-manager.d.ts +17 -0
- package/src/types/react-native-webrtc.d.ts +47 -0
- package/src/types.ts +133 -0
- package/src/ui/VaniraWidget.ts +87 -0
- package/src/ui/abstraction/AbstractWidgetProvider.ts +18 -0
- package/src/ui/abstraction/interfaces.ts +12 -0
- package/src/ui/adapters/VaniraChatAdapter.ts +42 -0
- package/src/ui/components/AvatarView.ts +81 -0
- package/src/ui/components/ChatWindow.ts +263 -0
- package/src/ui/components/FloatingButton.ts +163 -0
- package/src/ui/components/FloatingWelcomeChips.ts +137 -0
- package/src/ui/components/Panel.ts +120 -0
- package/src/ui/components/VoiceOrb.ts +79 -0
- package/src/ui/components/VoiceOverlay.ts +497 -0
- package/src/ui/components/index.ts +7 -0
- package/src/ui/factory/WidgetFactory.ts +16 -0
- package/src/ui/icons_data.ts +2 -0
- package/src/ui/presets/WidgetPresetRenderer.ts +1802 -0
- package/src/ui/presets/types.ts +16 -0
- package/src/ui/providers/VaniraInternalProvider.ts +1066 -0
- package/src/ui/styles/index.ts +323 -0
- package/src/ui/styles/keyframes.ts +76 -0
- package/src/ui/styles/theme.ts +57 -0
- package/src/ui/styles/widget.css.ts +838 -0
- package/src/ui/utils.ts +37 -0
- package/src/ui/views/AbstractChatView.ts +93 -0
- package/src/ui/views/AbstractVoiceView.ts +57 -0
- package/src/ui/views/AvatarOnlyView.ts +78 -0
- package/src/ui/views/ChatAvatarView.ts +66 -0
- package/src/ui/views/ChatOnlyView.ts +28 -0
- package/src/ui/views/ChatVoiceView.ts +15 -0
- package/src/ui/views/VoiceOnlyView.ts +25 -0
- package/src/ui/views/index.ts +5 -0
package/src/ui/utils.ts
ADDED
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Clean up LaTeX mathematical formatting from a string into a clean, human-readable plain text.
|
|
3
|
+
*/
|
|
4
|
+
export function cleanLatexText(text: string): string {
|
|
5
|
+
if (!text) return '';
|
|
6
|
+
return text
|
|
7
|
+
// 1. Fractions: \frac{a}{b} -> a/b
|
|
8
|
+
.replace(/\\frac\{([^}]+)\}\{([^}]+)\}/g, '$1/$2')
|
|
9
|
+
// 2. Square roots: \sqrt{a} -> √a
|
|
10
|
+
.replace(/\\sqrt\{([^}]+)\}/g, '√$1')
|
|
11
|
+
.replace(/\\sqrt(?![a-zA-Z])/g, '√')
|
|
12
|
+
.replace(/\bsqrt\b/gi, '√')
|
|
13
|
+
// 3. Delimiters: \left and \right
|
|
14
|
+
.replace(/\\left(?![a-zA-Z])/g, '')
|
|
15
|
+
.replace(/\\right(?![a-zA-Z])/g, '')
|
|
16
|
+
// 4. Text block: \text{abc} -> abc
|
|
17
|
+
.replace(/\\text\{([^}]+)\}/g, '$1')
|
|
18
|
+
.replace(/\\text\{([^}]+)$/g, '$1') // in case of missing closing brace like \text{ (cannot be simplified further)
|
|
19
|
+
.replace(/\\text(?![a-zA-Z])/g, '') // remove any dangling \text
|
|
20
|
+
// 5. Common math symbols
|
|
21
|
+
.replace(/\\times(?![a-zA-Z])/g, '×')
|
|
22
|
+
.replace(/\\div(?![a-zA-Z])/g, '÷')
|
|
23
|
+
.replace(/\\pm(?![a-zA-Z])/g, '±')
|
|
24
|
+
.replace(/\\ge(q)?(?![a-zA-Z])/g, '≥')
|
|
25
|
+
.replace(/\\le(q)?(?![a-zA-Z])/g, '≤')
|
|
26
|
+
.replace(/\\ne(q)?(?![a-zA-Z])/g, '≠')
|
|
27
|
+
.replace(/\\approx(?![a-zA-Z])/g, '≈')
|
|
28
|
+
.replace(/\\cdot(?![a-zA-Z])/g, '·')
|
|
29
|
+
.replace(/\\degree(?![a-zA-Z])/g, '°')
|
|
30
|
+
.replace(/\\pi(?![a-zA-Z])/g, 'π')
|
|
31
|
+
.replace(/\\theta(?![a-zA-Z])/g, 'θ')
|
|
32
|
+
.replace(/\\infty(?![a-zA-Z])/g, '∞')
|
|
33
|
+
// Strip any remaining curly braces from LaTeX commands
|
|
34
|
+
.replace(/[{}]/g, '')
|
|
35
|
+
// Clean up double/multiple spaces to a single space
|
|
36
|
+
.replace(/ +/g, ' ');
|
|
37
|
+
}
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
import { ChatWindow, VoiceOverlay } from '../components';
|
|
2
|
+
import { icons } from '../styles';
|
|
3
|
+
|
|
4
|
+
export abstract class AbstractChatView {
|
|
5
|
+
protected element: HTMLDivElement;
|
|
6
|
+
protected chatWindow!: ChatWindow;
|
|
7
|
+
protected overlay!: VoiceOverlay;
|
|
8
|
+
protected voiceTrigger!: HTMLButtonElement;
|
|
9
|
+
|
|
10
|
+
constructor(
|
|
11
|
+
protected onSendMessage: (msg: string) => void,
|
|
12
|
+
protected onStartCall: () => void,
|
|
13
|
+
protected onHangup: () => void,
|
|
14
|
+
protected primaryColor: string = '#000000',
|
|
15
|
+
protected secondaryColor: string = '#111111',
|
|
16
|
+
protected onCallEnded?: (durationMs: number, startedAt: number) => void
|
|
17
|
+
) {
|
|
18
|
+
this.element = document.createElement('div');
|
|
19
|
+
this.element.style.flex = '1'; // Fill parent (widget-body)
|
|
20
|
+
this.element.style.display = 'flex';
|
|
21
|
+
this.element.style.flexDirection = 'column';
|
|
22
|
+
this.element.style.minHeight = '0'; // Crucial for flex scrolling
|
|
23
|
+
this.element.style.position = 'relative'; // Added from VoiceView
|
|
24
|
+
|
|
25
|
+
// Child classes will append specific elements (Avatar, etc)
|
|
26
|
+
// Then call setupChat()
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
protected setupChat() {
|
|
30
|
+
this.chatWindow = new ChatWindow((msg) => this.onSendMessage(msg));
|
|
31
|
+
const chatEl = this.chatWindow.getElement();
|
|
32
|
+
chatEl.style.flex = '1';
|
|
33
|
+
this.element.appendChild(chatEl);
|
|
34
|
+
|
|
35
|
+
this.injectVoiceTrigger();
|
|
36
|
+
|
|
37
|
+
this.overlay = new VoiceOverlay(() => this.onHangup(), this.primaryColor, this.secondaryColor, this.onCallEnded);
|
|
38
|
+
this.element.appendChild(this.overlay.getElement());
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
protected injectVoiceTrigger() {
|
|
42
|
+
const triggerBtn = document.createElement('button');
|
|
43
|
+
this.voiceTrigger = triggerBtn;
|
|
44
|
+
triggerBtn.className = 'voice-btn-simple';
|
|
45
|
+
triggerBtn.innerHTML = `<div class="voice-btn-icon">${icons.audioLines}</div>`;
|
|
46
|
+
triggerBtn.onclick = () => this.onStartCall();
|
|
47
|
+
|
|
48
|
+
// Synchronous injection since ChatWindow is already constructed
|
|
49
|
+
const inputArea = this.chatWindow.getElement().querySelector('.chat-input-area');
|
|
50
|
+
|
|
51
|
+
if (inputArea) {
|
|
52
|
+
inputArea.insertBefore(this.voiceTrigger, inputArea.firstChild);
|
|
53
|
+
} else {
|
|
54
|
+
console.warn('VaniraSDK: Failed to inject voice trigger', { inputArea });
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
public getElement(): HTMLDivElement {
|
|
59
|
+
return this.element;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
public getChatWindow(): ChatWindow {
|
|
63
|
+
return this.chatWindow;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
public setCallActive(active: boolean) {
|
|
67
|
+
if (active) {
|
|
68
|
+
this.overlay.show();
|
|
69
|
+
// User Request: Hide Chat Welcome & Chat Box during interaction
|
|
70
|
+
if (this.chatWindow) {
|
|
71
|
+
this.chatWindow.getElement().style.display = 'none';
|
|
72
|
+
}
|
|
73
|
+
} else {
|
|
74
|
+
this.overlay.hide();
|
|
75
|
+
// Restore functionality on hangup
|
|
76
|
+
if (this.chatWindow) {
|
|
77
|
+
this.chatWindow.getElement().style.display = 'flex';
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
public setStatus(status: 'connecting' | 'connected' | 'disconnected' | 'error', errorMsg?: string) {
|
|
83
|
+
this.overlay.setStatus(status, errorMsg);
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
public setTranscription(text: string, isFinal: boolean) {
|
|
87
|
+
this.overlay.setTranscription(text, isFinal);
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
public setVideoTrack(track: MediaStreamTrack) {
|
|
91
|
+
this.overlay.setVideoTrack(track);
|
|
92
|
+
}
|
|
93
|
+
}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import { VoiceOverlay } from '../components';
|
|
2
|
+
|
|
3
|
+
export abstract class AbstractVoiceView {
|
|
4
|
+
protected element: HTMLDivElement;
|
|
5
|
+
protected overlay!: VoiceOverlay;
|
|
6
|
+
protected onStartCall: (behavior?: 'continue' | 'new') => void;
|
|
7
|
+
protected onHangup: () => void;
|
|
8
|
+
protected primaryColor: string;
|
|
9
|
+
protected secondaryColor: string;
|
|
10
|
+
protected onCallEnded?: (durationMs: number, startedAt: number) => void;
|
|
11
|
+
|
|
12
|
+
constructor(
|
|
13
|
+
onStartCall: (behavior?: 'continue' | 'new') => void,
|
|
14
|
+
onHangup: () => void,
|
|
15
|
+
primaryColor: string = '#000000',
|
|
16
|
+
secondaryColor: string = '#111111',
|
|
17
|
+
onCallEnded?: (durationMs: number, startedAt: number) => void
|
|
18
|
+
) {
|
|
19
|
+
this.onStartCall = onStartCall;
|
|
20
|
+
this.onHangup = onHangup;
|
|
21
|
+
this.primaryColor = primaryColor;
|
|
22
|
+
this.secondaryColor = secondaryColor;
|
|
23
|
+
this.onCallEnded = onCallEnded;
|
|
24
|
+
this.element = document.createElement('div');
|
|
25
|
+
this.element.style.height = '100%';
|
|
26
|
+
this.element.style.position = 'relative';
|
|
27
|
+
|
|
28
|
+
// Child classes implement specific init
|
|
29
|
+
// BUT calling initOverlay here is common
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
protected initOverlay() {
|
|
33
|
+
this.overlay = new VoiceOverlay(() => this.onHangup(), this.primaryColor, this.secondaryColor, this.onCallEnded);
|
|
34
|
+
this.element.appendChild(this.overlay.getElement());
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
public getElement(): HTMLDivElement {
|
|
38
|
+
return this.element;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
public setCallActive(active: boolean) {
|
|
42
|
+
if (active) this.overlay.show();
|
|
43
|
+
else this.overlay.hide();
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
public setStatus(status: 'connecting' | 'connected' | 'disconnected' | 'error', errorMsg?: string) {
|
|
47
|
+
this.overlay.setStatus(status, errorMsg);
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
public setTranscription(text: string, isFinal: boolean) {
|
|
51
|
+
this.overlay.setTranscription(text, isFinal);
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
public setVideoTrack(track: MediaStreamTrack) {
|
|
55
|
+
this.overlay.setVideoTrack(track);
|
|
56
|
+
}
|
|
57
|
+
}
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
import { AvatarView } from '../components';
|
|
2
|
+
import { icons } from '../styles';
|
|
3
|
+
import { AbstractVoiceView } from './AbstractVoiceView';
|
|
4
|
+
|
|
5
|
+
export class AvatarOnlyView extends AbstractVoiceView {
|
|
6
|
+
private avatarView: AvatarView;
|
|
7
|
+
private startCallBtn: HTMLButtonElement;
|
|
8
|
+
private controlsContainer: HTMLDivElement;
|
|
9
|
+
|
|
10
|
+
constructor(
|
|
11
|
+
onStartCall: () => void,
|
|
12
|
+
onHangup: () => void,
|
|
13
|
+
primaryColor: string = '#000000',
|
|
14
|
+
secondaryColor: string = '#111111',
|
|
15
|
+
onCallEnded?: (durationMs: number, startedAt: number) => void
|
|
16
|
+
) {
|
|
17
|
+
super(onStartCall, onHangup, primaryColor, secondaryColor, onCallEnded);
|
|
18
|
+
|
|
19
|
+
// Ensure flex layout
|
|
20
|
+
this.element.style.display = 'flex';
|
|
21
|
+
this.element.style.flexDirection = 'column';
|
|
22
|
+
|
|
23
|
+
// 1. Avatar View (Idle State matching Overlay Card)
|
|
24
|
+
this.avatarView = new AvatarView();
|
|
25
|
+
const avatarEl = this.avatarView.getElement();
|
|
26
|
+
// Match VoiceOverlay VideoContainer styles
|
|
27
|
+
avatarEl.style.width = '100%';
|
|
28
|
+
avatarEl.style.maxWidth = '300px';
|
|
29
|
+
avatarEl.style.aspectRatio = '1/1';
|
|
30
|
+
avatarEl.style.borderRadius = '16px';
|
|
31
|
+
avatarEl.style.overflow = 'hidden';
|
|
32
|
+
avatarEl.style.margin = 'auto'; // Center vertically and horizontally
|
|
33
|
+
avatarEl.style.position = 'relative'; // Ensure proper stacking
|
|
34
|
+
|
|
35
|
+
this.element.appendChild(avatarEl);
|
|
36
|
+
|
|
37
|
+
// 2. Start Call Controls
|
|
38
|
+
this.controlsContainer = document.createElement('div');
|
|
39
|
+
this.controlsContainer.className = 'widget-body';
|
|
40
|
+
this.controlsContainer.style.position = 'absolute';
|
|
41
|
+
this.controlsContainer.style.bottom = '20px';
|
|
42
|
+
this.controlsContainer.style.width = '100%';
|
|
43
|
+
this.controlsContainer.style.zIndex = '10';
|
|
44
|
+
|
|
45
|
+
const controls = document.createElement('div');
|
|
46
|
+
controls.className = 'controls';
|
|
47
|
+
|
|
48
|
+
this.startCallBtn = document.createElement('button');
|
|
49
|
+
this.startCallBtn.className = 'control-btn primary';
|
|
50
|
+
this.startCallBtn.innerHTML = `${icons.phone} <span>Start Call</span>`;
|
|
51
|
+
this.startCallBtn.onclick = () => this.onStartCall();
|
|
52
|
+
|
|
53
|
+
controls.appendChild(this.startCallBtn);
|
|
54
|
+
this.controlsContainer.appendChild(controls);
|
|
55
|
+
this.element.appendChild(this.controlsContainer);
|
|
56
|
+
|
|
57
|
+
// 3. Overlay
|
|
58
|
+
this.initOverlay();
|
|
59
|
+
this.overlay.setMode('avatar');
|
|
60
|
+
// REVERTED Full Screen: this.overlay.setFullScreen(true);
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
public getAvatarView(): AvatarView {
|
|
64
|
+
return this.avatarView;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
public override setCallActive(active: boolean) {
|
|
68
|
+
if (active) {
|
|
69
|
+
this.overlay.setMode('avatar');
|
|
70
|
+
}
|
|
71
|
+
super.setCallActive(active);
|
|
72
|
+
if (active) {
|
|
73
|
+
this.controlsContainer.style.display = 'none';
|
|
74
|
+
} else {
|
|
75
|
+
this.controlsContainer.style.display = 'block';
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
}
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import { AbstractChatView } from './AbstractChatView';
|
|
2
|
+
import { icons } from '../styles';
|
|
3
|
+
|
|
4
|
+
export class ChatAvatarView extends AbstractChatView {
|
|
5
|
+
|
|
6
|
+
constructor(
|
|
7
|
+
onSendMessage: (msg: string) => void,
|
|
8
|
+
onStartCall: () => void,
|
|
9
|
+
onHangup: () => void,
|
|
10
|
+
primaryColor: string = '#000000',
|
|
11
|
+
secondaryColor: string = '#111111',
|
|
12
|
+
onCallEnded?: (durationMs: number, startedAt: number) => void
|
|
13
|
+
) {
|
|
14
|
+
super(onSendMessage, onStartCall, onHangup, primaryColor, secondaryColor, onCallEnded);
|
|
15
|
+
// No top AvatarView anymore! Just standard chat setup.
|
|
16
|
+
this.setupChat();
|
|
17
|
+
this.overlay.setMode('avatar');
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
// Override to inject the unique Circular Video Button
|
|
21
|
+
protected override injectVoiceTrigger() {
|
|
22
|
+
const triggerBtn = document.createElement('button');
|
|
23
|
+
this.voiceTrigger = triggerBtn;
|
|
24
|
+
triggerBtn.className = 'voice-btn-simple';
|
|
25
|
+
// Custom styling for Avatar Mode
|
|
26
|
+
triggerBtn.style.overflow = 'hidden'; // Clip video
|
|
27
|
+
triggerBtn.style.padding = '0';
|
|
28
|
+
triggerBtn.style.border = '1.5px solid #e5e7eb'; // Clean border
|
|
29
|
+
|
|
30
|
+
// Video Loop (Simli Jenna or equiv)
|
|
31
|
+
triggerBtn.innerHTML = `
|
|
32
|
+
<video
|
|
33
|
+
src="https://www.simli.com/jenna.mp4"
|
|
34
|
+
autoplay loop muted pip="false" playsinline
|
|
35
|
+
style="width: 100%; height: 100%; object-fit: cover; border-radius: 50%;">
|
|
36
|
+
</video>
|
|
37
|
+
<div style="position: absolute; bottom: -2px; right: -2px; background: white; border-radius: 50%; padding: 2px; box-shadow: 0 1px 2px rgba(0,0,0,0.1);">
|
|
38
|
+
${icons.audioLines.replace('width="24"', 'width="12"').replace('height="24"', 'height="12"')}
|
|
39
|
+
</div>
|
|
40
|
+
`;
|
|
41
|
+
|
|
42
|
+
// Ensure small icon style if replacement didn't work (regex safely)
|
|
43
|
+
const iconDiv = triggerBtn.querySelector('div');
|
|
44
|
+
if (iconDiv) {
|
|
45
|
+
const svg = iconDiv.querySelector('svg');
|
|
46
|
+
if (svg) {
|
|
47
|
+
svg.style.width = '12px';
|
|
48
|
+
svg.style.height = '12px';
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
triggerBtn.onclick = () => this.onStartCall();
|
|
53
|
+
|
|
54
|
+
// Synchronous injection
|
|
55
|
+
const inputArea = this.chatWindow.getElement().querySelector('.chat-input-area');
|
|
56
|
+
const sendBtn = inputArea?.querySelector('.chat-send-btn');
|
|
57
|
+
|
|
58
|
+
if (inputArea && sendBtn) {
|
|
59
|
+
inputArea.insertBefore(this.voiceTrigger, sendBtn);
|
|
60
|
+
} else {
|
|
61
|
+
console.warn('VaniraSDK: Failed to inject voice trigger', { inputArea, sendBtn });
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
// No getAvatarView method anymore. VaniraInternalProvider should check for capability or cast.
|
|
66
|
+
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { ChatWindow } from '../components';
|
|
2
|
+
|
|
3
|
+
export class ChatOnlyView {
|
|
4
|
+
private element: HTMLDivElement;
|
|
5
|
+
private chatWindow: ChatWindow;
|
|
6
|
+
|
|
7
|
+
constructor(
|
|
8
|
+
private onSendMessage: (msg: string) => void
|
|
9
|
+
) {
|
|
10
|
+
this.element = document.createElement('div');
|
|
11
|
+
this.element.style.flex = '1';
|
|
12
|
+
this.element.style.width = '100%';
|
|
13
|
+
this.element.style.minHeight = '0'; // Crucial for flex scrolling
|
|
14
|
+
this.element.style.display = 'flex';
|
|
15
|
+
this.element.style.flexDirection = 'column';
|
|
16
|
+
|
|
17
|
+
this.chatWindow = new ChatWindow((msg) => this.onSendMessage(msg));
|
|
18
|
+
this.element.appendChild(this.chatWindow.getElement());
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
public getElement(): HTMLDivElement {
|
|
22
|
+
return this.element;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
public getChatWindow(): ChatWindow {
|
|
26
|
+
return this.chatWindow;
|
|
27
|
+
}
|
|
28
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { AbstractChatView } from './AbstractChatView';
|
|
2
|
+
|
|
3
|
+
export class ChatVoiceView extends AbstractChatView {
|
|
4
|
+
constructor(
|
|
5
|
+
onSendMessage: (msg: string) => void,
|
|
6
|
+
onStartCall: () => void,
|
|
7
|
+
onHangup: () => void,
|
|
8
|
+
primaryColor: string = '#000000',
|
|
9
|
+
secondaryColor: string = '#111111',
|
|
10
|
+
onCallEnded?: (durationMs: number, startedAt: number) => void
|
|
11
|
+
) {
|
|
12
|
+
super(onSendMessage, onStartCall, onHangup, primaryColor, secondaryColor, onCallEnded);
|
|
13
|
+
this.setupChat();
|
|
14
|
+
}
|
|
15
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { VoiceOrb } from '../components';
|
|
2
|
+
import { AbstractVoiceView } from './AbstractVoiceView';
|
|
3
|
+
|
|
4
|
+
export class VoiceOnlyView extends AbstractVoiceView {
|
|
5
|
+
private voiceOrb: VoiceOrb;
|
|
6
|
+
|
|
7
|
+
constructor(
|
|
8
|
+
onStartCall: (behavior?: 'continue' | 'new') => void,
|
|
9
|
+
onHangup: () => void,
|
|
10
|
+
primaryColor: string = '#000000',
|
|
11
|
+
secondaryColor: string = '#111111',
|
|
12
|
+
onCallEnded?: (durationMs: number, startedAt: number) => void
|
|
13
|
+
) {
|
|
14
|
+
super(onStartCall, onHangup, primaryColor, secondaryColor, onCallEnded);
|
|
15
|
+
|
|
16
|
+
this.element.style.background = '#f9fafb';
|
|
17
|
+
|
|
18
|
+
this.voiceOrb = new VoiceOrb((behavior) => {
|
|
19
|
+
this.onStartCall(behavior);
|
|
20
|
+
});
|
|
21
|
+
this.element.appendChild(this.voiceOrb.getElement());
|
|
22
|
+
|
|
23
|
+
this.initOverlay();
|
|
24
|
+
}
|
|
25
|
+
}
|