@talk2view/sdk 0.3.2 → 0.5.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 (164) hide show
  1. package/dist/client.d.ts +1 -1
  2. package/dist/client.d.ts.map +1 -1
  3. package/dist/client.js +4 -4
  4. package/dist/client.js.map +1 -1
  5. package/dist/event-emitter.d.ts +7 -0
  6. package/dist/event-emitter.d.ts.map +1 -0
  7. package/dist/event-emitter.js +23 -0
  8. package/dist/event-emitter.js.map +1 -0
  9. package/dist/index.d.ts +78 -2
  10. package/dist/index.d.ts.map +1 -1
  11. package/dist/index.js +312 -6
  12. package/dist/index.js.map +1 -1
  13. package/dist/react/T2VProvider.js +1 -1
  14. package/dist/react/T2VProvider.js.map +1 -1
  15. package/dist/react/index.d.ts +2 -1
  16. package/dist/react/index.d.ts.map +1 -1
  17. package/dist/react/useT2VChat.d.ts +6 -22
  18. package/dist/react/useT2VChat.d.ts.map +1 -1
  19. package/dist/react/useT2VChat.js +34 -218
  20. package/dist/react/useT2VChat.js.map +1 -1
  21. package/dist/sessions.d.ts.map +1 -1
  22. package/dist/sessions.js +3 -0
  23. package/dist/sessions.js.map +1 -1
  24. package/dist/tools.d.ts +5 -0
  25. package/dist/tools.d.ts.map +1 -1
  26. package/dist/tools.js +16 -2
  27. package/dist/tools.js.map +1 -1
  28. package/dist/types.d.ts +45 -0
  29. package/dist/types.d.ts.map +1 -1
  30. package/dist/ui/components/ApprovalCard.d.ts +10 -0
  31. package/dist/ui/components/ApprovalCard.d.ts.map +1 -0
  32. package/dist/ui/components/ApprovalCard.js +60 -0
  33. package/dist/ui/components/ApprovalCard.js.map +1 -0
  34. package/dist/ui/components/{T2VChatHeader.d.ts → ChatHeader.d.ts} +4 -4
  35. package/dist/ui/components/ChatHeader.d.ts.map +1 -0
  36. package/dist/ui/components/ChatHeader.js +126 -0
  37. package/dist/ui/components/ChatHeader.js.map +1 -0
  38. package/dist/ui/components/ChatPanel.d.ts +9 -0
  39. package/dist/ui/components/ChatPanel.d.ts.map +1 -0
  40. package/dist/ui/components/ChatPanel.js +37 -0
  41. package/dist/ui/components/ChatPanel.js.map +1 -0
  42. package/dist/ui/components/ChatWidget.d.ts +5 -0
  43. package/dist/ui/components/ChatWidget.d.ts.map +1 -0
  44. package/dist/ui/components/ChatWidget.js +27 -0
  45. package/dist/ui/components/ChatWidget.js.map +1 -0
  46. package/dist/ui/components/CodeBlock.d.ts +6 -0
  47. package/dist/ui/components/CodeBlock.d.ts.map +1 -0
  48. package/dist/ui/components/CodeBlock.js +79 -0
  49. package/dist/ui/components/CodeBlock.js.map +1 -0
  50. package/dist/ui/components/Composer.d.ts +14 -0
  51. package/dist/ui/components/Composer.d.ts.map +1 -0
  52. package/dist/ui/components/Composer.js +172 -0
  53. package/dist/ui/components/Composer.js.map +1 -0
  54. package/dist/ui/components/LoginForm.d.ts +5 -0
  55. package/dist/ui/components/LoginForm.d.ts.map +1 -0
  56. package/dist/ui/components/LoginForm.js +37 -0
  57. package/dist/ui/components/LoginForm.js.map +1 -0
  58. package/dist/ui/components/MarkdownRenderer.d.ts +5 -0
  59. package/dist/ui/components/MarkdownRenderer.d.ts.map +1 -0
  60. package/dist/ui/components/MarkdownRenderer.js +28 -0
  61. package/dist/ui/components/MarkdownRenderer.js.map +1 -0
  62. package/dist/ui/components/MessageActions.d.ts +6 -0
  63. package/dist/ui/components/MessageActions.d.ts.map +1 -0
  64. package/dist/ui/components/MessageActions.js +43 -0
  65. package/dist/ui/components/MessageActions.js.map +1 -0
  66. package/dist/ui/components/MessageBubble.d.ts +16 -0
  67. package/dist/ui/components/MessageBubble.d.ts.map +1 -0
  68. package/dist/ui/components/MessageBubble.js +71 -0
  69. package/dist/ui/components/MessageBubble.js.map +1 -0
  70. package/dist/ui/components/MessageList.d.ts +10 -0
  71. package/dist/ui/components/MessageList.d.ts.map +1 -0
  72. package/dist/ui/components/MessageList.js +69 -0
  73. package/dist/ui/components/MessageList.js.map +1 -0
  74. package/dist/ui/components/SettingsPanel.d.ts +11 -0
  75. package/dist/ui/components/SettingsPanel.d.ts.map +1 -0
  76. package/dist/ui/components/{SettingsView.js → SettingsPanel.js} +27 -27
  77. package/dist/ui/components/SettingsPanel.js.map +1 -0
  78. package/dist/ui/components/Shimmer.d.ts +2 -0
  79. package/dist/ui/components/Shimmer.d.ts.map +1 -0
  80. package/dist/ui/components/Shimmer.js +10 -0
  81. package/dist/ui/components/Shimmer.js.map +1 -0
  82. package/dist/ui/components/Talk2View.d.ts +21 -0
  83. package/dist/ui/components/Talk2View.d.ts.map +1 -0
  84. package/dist/ui/components/Talk2View.js +79 -0
  85. package/dist/ui/components/Talk2View.js.map +1 -0
  86. package/dist/ui/components/ThinkingBlock.d.ts +7 -0
  87. package/dist/ui/components/ThinkingBlock.d.ts.map +1 -0
  88. package/dist/ui/components/ThinkingBlock.js +64 -0
  89. package/dist/ui/components/ThinkingBlock.js.map +1 -0
  90. package/dist/ui/components/ToolDisplay.d.ts +28 -0
  91. package/dist/ui/components/ToolDisplay.d.ts.map +1 -0
  92. package/dist/ui/components/ToolDisplay.js +123 -0
  93. package/dist/ui/components/ToolDisplay.js.map +1 -0
  94. package/dist/ui/components/WelcomeScreen.d.ts +6 -0
  95. package/dist/ui/components/WelcomeScreen.d.ts.map +1 -0
  96. package/dist/ui/components/WelcomeScreen.js +18 -0
  97. package/dist/ui/components/WelcomeScreen.js.map +1 -0
  98. package/dist/ui/context.d.ts +29 -0
  99. package/dist/ui/context.d.ts.map +1 -0
  100. package/dist/ui/context.js +16 -0
  101. package/dist/ui/context.js.map +1 -0
  102. package/dist/ui/index.d.ts +24 -37
  103. package/dist/ui/index.d.ts.map +1 -1
  104. package/dist/ui/index.js +23 -35
  105. package/dist/ui/index.js.map +1 -1
  106. package/dist/ui/styles.d.ts +2 -0
  107. package/dist/ui/styles.d.ts.map +1 -0
  108. package/dist/ui/styles.js +91 -0
  109. package/dist/ui/styles.js.map +1 -0
  110. package/dist/ui/theme.d.ts +11 -0
  111. package/dist/ui/theme.d.ts.map +1 -0
  112. package/dist/ui/theme.js +70 -0
  113. package/dist/ui/theme.js.map +1 -0
  114. package/package.json +5 -10
  115. package/dist/ui/components/LoginModal.d.ts +0 -10
  116. package/dist/ui/components/LoginModal.d.ts.map +0 -1
  117. package/dist/ui/components/LoginModal.js +0 -138
  118. package/dist/ui/components/LoginModal.js.map +0 -1
  119. package/dist/ui/components/SettingsView.d.ts +0 -11
  120. package/dist/ui/components/SettingsView.d.ts.map +0 -1
  121. package/dist/ui/components/SettingsView.js.map +0 -1
  122. package/dist/ui/components/T2VAssistantModal.d.ts +0 -31
  123. package/dist/ui/components/T2VAssistantModal.d.ts.map +0 -1
  124. package/dist/ui/components/T2VAssistantModal.js +0 -151
  125. package/dist/ui/components/T2VAssistantModal.js.map +0 -1
  126. package/dist/ui/components/T2VAssistantProvider.d.ts +0 -42
  127. package/dist/ui/components/T2VAssistantProvider.d.ts.map +0 -1
  128. package/dist/ui/components/T2VAssistantProvider.js +0 -66
  129. package/dist/ui/components/T2VAssistantProvider.js.map +0 -1
  130. package/dist/ui/components/T2VChatHeader.d.ts.map +0 -1
  131. package/dist/ui/components/T2VChatHeader.js +0 -112
  132. package/dist/ui/components/T2VChatHeader.js.map +0 -1
  133. package/dist/ui/components/T2VComposer.d.ts +0 -11
  134. package/dist/ui/components/T2VComposer.d.ts.map +0 -1
  135. package/dist/ui/components/T2VComposer.js +0 -124
  136. package/dist/ui/components/T2VComposer.js.map +0 -1
  137. package/dist/ui/components/T2VDictationAdapter.d.ts +0 -18
  138. package/dist/ui/components/T2VDictationAdapter.d.ts.map +0 -1
  139. package/dist/ui/components/T2VDictationAdapter.js +0 -126
  140. package/dist/ui/components/T2VDictationAdapter.js.map +0 -1
  141. package/dist/ui/components/T2VLoginGate.d.ts +0 -23
  142. package/dist/ui/components/T2VLoginGate.d.ts.map +0 -1
  143. package/dist/ui/components/T2VLoginGate.js +0 -11
  144. package/dist/ui/components/T2VLoginGate.js.map +0 -1
  145. package/dist/ui/components/T2VThread.d.ts +0 -25
  146. package/dist/ui/components/T2VThread.d.ts.map +0 -1
  147. package/dist/ui/components/T2VThread.js +0 -66
  148. package/dist/ui/components/T2VThread.js.map +0 -1
  149. package/dist/ui/components/T2VToolFallback.d.ts +0 -11
  150. package/dist/ui/components/T2VToolFallback.d.ts.map +0 -1
  151. package/dist/ui/components/T2VToolFallback.js +0 -209
  152. package/dist/ui/components/T2VToolFallback.js.map +0 -1
  153. package/dist/ui/runtime/convertMessage.d.ts +0 -17
  154. package/dist/ui/runtime/convertMessage.d.ts.map +0 -1
  155. package/dist/ui/runtime/convertMessage.js +0 -77
  156. package/dist/ui/runtime/convertMessage.js.map +0 -1
  157. package/dist/ui/runtime/useT2VRuntime.d.ts +0 -42
  158. package/dist/ui/runtime/useT2VRuntime.d.ts.map +0 -1
  159. package/dist/ui/runtime/useT2VRuntime.js +0 -62
  160. package/dist/ui/runtime/useT2VRuntime.js.map +0 -1
  161. package/dist/ui/themes/tailwind-preset.d.ts +0 -43
  162. package/dist/ui/themes/tailwind-preset.d.ts.map +0 -1
  163. package/dist/ui/themes/tailwind-preset.js +0 -43
  164. package/dist/ui/themes/tailwind-preset.js.map +0 -1
@@ -0,0 +1,172 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ /**
3
+ * Composer — text input + mic button for sending messages.
4
+ *
5
+ * - Auto-resizing textarea (min 1 row, max ~120px).
6
+ * - Send on Enter, Shift+Enter inserts newline.
7
+ * - Disabled while loading.
8
+ * - Mic button records audio via MediaRecorder, sends to t2v.transcribe(),
9
+ * and inserts the transcript into the textarea.
10
+ * - Prefers audio/webm;codecs=opus, falls back to audio/webm.
11
+ * - STT model/language from useUserPreferences + usePartnerConfig.
12
+ * - Send button uses accent color when text is present, border color when empty.
13
+ */
14
+ import { useCallback, useEffect, useRef, useState } from 'react';
15
+ import { Mic, Send, Square, Loader2 } from 'lucide-react';
16
+ import { useChat } from '../context';
17
+ import { useTalk2View } from '../context';
18
+ import { useUserPreferences } from '../../react/useUserPreferences';
19
+ import { usePartnerConfig } from '../../react/usePartnerConfig';
20
+ export function Composer() {
21
+ const { sendMessage, isLoading } = useChat();
22
+ const { t2v } = useTalk2View();
23
+ const { preferences } = useUserPreferences();
24
+ const { config: partnerConfig } = usePartnerConfig();
25
+ const [text, setText] = useState('');
26
+ const [isRecording, setIsRecording] = useState(false);
27
+ const [isTranscribing, setIsTranscribing] = useState(false);
28
+ const textareaRef = useRef(null);
29
+ const mediaRecorderRef = useRef(null);
30
+ const chunksRef = useRef([]);
31
+ // Auto-resize textarea
32
+ useEffect(() => {
33
+ const el = textareaRef.current;
34
+ if (!el)
35
+ return;
36
+ el.style.height = 'auto';
37
+ el.style.height = `${Math.min(el.scrollHeight, 120)}px`;
38
+ }, [text]);
39
+ const handleSend = useCallback(() => {
40
+ const trimmed = text.trim();
41
+ if (!trimmed || isLoading)
42
+ return;
43
+ setText('');
44
+ sendMessage(trimmed).catch(console.error);
45
+ }, [text, isLoading, sendMessage]);
46
+ const handleKeyDown = useCallback((e) => {
47
+ if (e.key === 'Enter' && !e.shiftKey) {
48
+ e.preventDefault();
49
+ handleSend();
50
+ }
51
+ }, [handleSend]);
52
+ const handleMic = useCallback(async () => {
53
+ if (isRecording) {
54
+ if (mediaRecorderRef.current?.state === 'recording') {
55
+ mediaRecorderRef.current.stop();
56
+ }
57
+ setIsRecording(false);
58
+ return;
59
+ }
60
+ try {
61
+ const stream = await navigator.mediaDevices.getUserMedia({ audio: true });
62
+ const mimeType = MediaRecorder.isTypeSupported('audio/webm;codecs=opus')
63
+ ? 'audio/webm;codecs=opus'
64
+ : 'audio/webm';
65
+ const recorder = new MediaRecorder(stream, { mimeType });
66
+ mediaRecorderRef.current = recorder;
67
+ chunksRef.current = [];
68
+ recorder.ondataavailable = (e) => {
69
+ if (e.data.size > 0)
70
+ chunksRef.current.push(e.data);
71
+ };
72
+ recorder.onstop = async () => {
73
+ stream.getTracks().forEach((t) => t.stop());
74
+ const chunks = chunksRef.current;
75
+ if (chunks.length === 0)
76
+ return;
77
+ setIsTranscribing(true);
78
+ try {
79
+ const blob = new Blob(chunks, { type: mimeType });
80
+ const formData = new FormData();
81
+ formData.append('file', blob, 'recording.webm');
82
+ const sttModel = preferences.sttModel ||
83
+ partnerConfig?.default_stt_model ||
84
+ 'faster-whisper-base';
85
+ const sttLanguage = preferences.sttLanguage;
86
+ formData.append('model', sttModel);
87
+ if (sttLanguage)
88
+ formData.append('language', sttLanguage);
89
+ const result = await t2v.transcribe(formData);
90
+ const transcript = result.text.trim();
91
+ if (transcript) {
92
+ setText((prev) => (prev ? `${prev} ${transcript}` : transcript));
93
+ }
94
+ }
95
+ catch (err) {
96
+ console.error('Transcription failed:', err);
97
+ }
98
+ finally {
99
+ setIsTranscribing(false);
100
+ }
101
+ };
102
+ recorder.start();
103
+ setIsRecording(true);
104
+ }
105
+ catch (err) {
106
+ console.error('Microphone access denied:', err);
107
+ }
108
+ }, [isRecording, t2v, preferences.sttModel, preferences.sttLanguage, partnerConfig?.default_stt_model]);
109
+ const hasText = text.trim().length > 0;
110
+ return (_jsxs("div", { style: {
111
+ display: 'flex',
112
+ alignItems: 'flex-end',
113
+ gap: '6px',
114
+ padding: '10px 12px',
115
+ borderTop: '1px solid var(--t2v-border)',
116
+ background: 'var(--t2v-bg)',
117
+ fontFamily: 'var(--t2v-font)',
118
+ }, children: [_jsx("textarea", { ref: textareaRef, value: text, onChange: (e) => setText(e.target.value), onKeyDown: handleKeyDown, disabled: isLoading, placeholder: "Type a message\u2026", rows: 1, style: {
119
+ flex: 1,
120
+ resize: 'none',
121
+ border: '1px solid var(--t2v-border)',
122
+ borderRadius: 'calc(var(--t2v-radius) * 0.75px)',
123
+ padding: '8px 10px',
124
+ fontSize: '14px',
125
+ lineHeight: 1.5,
126
+ fontFamily: 'var(--t2v-font)',
127
+ color: 'var(--t2v-foreground)',
128
+ background: 'var(--t2v-bg)',
129
+ outline: 'none',
130
+ minHeight: '36px',
131
+ maxHeight: '120px',
132
+ overflowY: 'auto',
133
+ transition: 'border-color 0.15s',
134
+ }, onFocus: (e) => {
135
+ e.currentTarget.style.borderColor = 'var(--t2v-accent)';
136
+ }, onBlur: (e) => {
137
+ e.currentTarget.style.borderColor = 'var(--t2v-border)';
138
+ } }), _jsx("button", { type: "button", onClick: () => { handleMic().catch(console.error); }, disabled: isTranscribing, "aria-label": isTranscribing
139
+ ? 'Transcribing…'
140
+ : isRecording
141
+ ? 'Stop recording'
142
+ : 'Voice input', style: {
143
+ width: '36px',
144
+ height: '36px',
145
+ flexShrink: 0,
146
+ borderRadius: 'calc(var(--t2v-radius) * 0.75px)',
147
+ border: 'none',
148
+ background: isRecording ? 'var(--t2v-error)' : 'var(--t2v-accent)',
149
+ color: 'var(--t2v-accent-foreground)',
150
+ cursor: isTranscribing ? 'wait' : 'pointer',
151
+ opacity: isTranscribing ? 0.6 : 1,
152
+ transition: 'background 0.15s, opacity 0.15s',
153
+ display: 'flex',
154
+ alignItems: 'center',
155
+ justifyContent: 'center',
156
+ }, children: isTranscribing ? _jsx(Loader2, { size: 16, style: { animation: 't2v-spin 0.8s linear infinite' } }) : isRecording ? _jsx(Square, { size: 16 }) : _jsx(Mic, { size: 16 }) }), _jsx("button", { type: "button", onClick: handleSend, disabled: isLoading || !hasText, "aria-label": "Send message", style: {
157
+ width: '36px',
158
+ height: '36px',
159
+ flexShrink: 0,
160
+ borderRadius: 'calc(var(--t2v-radius) * 0.75px)',
161
+ border: hasText ? 'none' : '1px solid var(--t2v-border)',
162
+ background: hasText ? 'var(--t2v-accent)' : 'transparent',
163
+ color: hasText ? 'var(--t2v-accent-foreground)' : 'var(--t2v-muted)',
164
+ cursor: hasText && !isLoading ? 'pointer' : 'default',
165
+ opacity: isLoading ? 0.5 : 1,
166
+ transition: 'background 0.15s, border 0.15s, color 0.15s, opacity 0.15s',
167
+ display: 'flex',
168
+ alignItems: 'center',
169
+ justifyContent: 'center',
170
+ }, children: _jsx(Send, { size: 16 }) })] }));
171
+ }
172
+ //# sourceMappingURL=Composer.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Composer.js","sourceRoot":"","sources":["../../../src/ui/components/Composer.tsx"],"names":[],"mappings":"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"}
@@ -0,0 +1,5 @@
1
+ export interface LoginFormProps {
2
+ signupUrl?: string;
3
+ }
4
+ export declare function LoginForm({ signupUrl }: LoginFormProps): import("react/jsx-runtime").JSX.Element;
5
+ //# sourceMappingURL=LoginForm.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"LoginForm.d.ts","sourceRoot":"","sources":["../../../src/ui/components/LoginForm.tsx"],"names":[],"mappings":"AAIA,MAAM,WAAW,cAAc;IAC7B,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,wBAAgB,SAAS,CAAC,EAAE,SAAS,EAAE,EAAE,cAAc,2CAgEtD"}
@@ -0,0 +1,37 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { useState } from 'react';
3
+ import { useT2VAuth } from '../../react/useT2VAuth';
4
+ import { LOGOS } from '../theme';
5
+ export function LoginForm({ signupUrl }) {
6
+ const { login, isLoading, error, clearError } = useT2VAuth();
7
+ const [email, setEmail] = useState('');
8
+ const [password, setPassword] = useState('');
9
+ const handleSubmit = async (e) => {
10
+ e.preventDefault();
11
+ if (!email || !password || isLoading)
12
+ return;
13
+ try {
14
+ await login(email, password);
15
+ }
16
+ catch {
17
+ // useT2VAuth already surfaces the message via the `error` state; swallow
18
+ // the rejection here so the dev overlay doesn't flag it as uncaught.
19
+ }
20
+ };
21
+ const inputStyle = {
22
+ width: '100%', padding: '10px 12px',
23
+ border: '1.5px solid var(--t2v-border)', borderRadius: 'calc(var(--t2v-radius) * 0.5px)',
24
+ fontFamily: 'var(--t2v-font)', fontSize: '14px',
25
+ background: 'var(--t2v-bg)', color: 'var(--t2v-foreground)',
26
+ outline: 'none', transition: 'border-color 0.15s',
27
+ boxSizing: 'border-box',
28
+ };
29
+ return (_jsxs("div", { style: { flex: 1, display: 'flex', flexDirection: 'column', alignItems: 'center', justifyContent: 'center', padding: '32px 24px', gap: '20px' }, children: [_jsx("img", { src: LOGOS.icon, alt: "Talk2View", style: { width: 36, height: 36 } }), _jsxs("div", { style: { textAlign: 'center' }, children: [_jsx("h2", { style: { margin: 0, fontSize: '16px', fontWeight: 600, fontFamily: 'var(--t2v-font)' }, children: "Sign in to Talk2View" }), _jsx("p", { style: { margin: '4px 0 0', fontSize: '13px', color: 'var(--t2v-muted)' }, children: "Enter your credentials to continue" })] }), error && (_jsx("div", { style: { width: '100%', maxWidth: '280px', padding: '8px 12px', background: 'rgba(220,38,38,0.06)', border: '1px solid rgba(220,38,38,0.15)', borderRadius: '6px', fontSize: '12px', color: 'var(--t2v-error)' }, children: error })), _jsxs("form", { onSubmit: handleSubmit, style: { width: '100%', maxWidth: '280px', display: 'flex', flexDirection: 'column', gap: '10px' }, children: [_jsxs("label", { style: { display: 'flex', flexDirection: 'column', gap: '4px' }, children: [_jsx("span", { style: { fontSize: '12px', fontWeight: 500, fontFamily: 'var(--t2v-font)', color: 'var(--t2v-foreground)' }, children: "Email" }), _jsx("input", { id: "t2v-email", type: "email", placeholder: "Email", value: email, onChange: (e) => { setEmail(e.target.value); clearError(); }, className: "t2v-focusable", style: inputStyle })] }), _jsxs("label", { style: { display: 'flex', flexDirection: 'column', gap: '4px' }, children: [_jsx("span", { style: { fontSize: '12px', fontWeight: 500, fontFamily: 'var(--t2v-font)', color: 'var(--t2v-foreground)' }, children: "Password" }), _jsx("input", { id: "t2v-password", type: "password", placeholder: "Password", value: password, onChange: (e) => { setPassword(e.target.value); clearError(); }, className: "t2v-focusable", style: inputStyle })] }), _jsx("button", { type: "submit", disabled: !email || !password || isLoading, className: "t2v-btn", style: {
30
+ width: '100%', padding: '10px', border: 'none', borderRadius: 'calc(var(--t2v-radius) * 0.5px)',
31
+ background: 'var(--t2v-accent)', color: 'var(--t2v-accent-foreground)',
32
+ fontFamily: 'var(--t2v-font)', fontSize: '14px', fontWeight: 500,
33
+ cursor: isLoading ? 'wait' : 'pointer', opacity: (!email || !password || isLoading) ? 0.6 : 1,
34
+ transition: 'opacity 0.15s',
35
+ }, children: isLoading ? 'Signing in...' : 'Sign in' })] }), signupUrl && (_jsxs("p", { style: { fontSize: '12px', color: 'var(--t2v-muted)' }, children: ["Don't have an account?", ' ', _jsx("a", { href: signupUrl, target: "_blank", rel: "noopener noreferrer", style: { color: 'var(--t2v-accent)', textDecoration: 'underline' }, children: "Sign up" })] }))] }));
36
+ }
37
+ //# sourceMappingURL=LoginForm.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"LoginForm.js","sourceRoot":"","sources":["../../../src/ui/components/LoginForm.tsx"],"names":[],"mappings":"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"}
@@ -0,0 +1,5 @@
1
+ export interface MarkdownRendererProps {
2
+ content: string;
3
+ }
4
+ export declare function MarkdownRenderer({ content }: MarkdownRendererProps): import("react/jsx-runtime").JSX.Element;
5
+ //# sourceMappingURL=MarkdownRenderer.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"MarkdownRenderer.d.ts","sourceRoot":"","sources":["../../../src/ui/components/MarkdownRenderer.tsx"],"names":[],"mappings":"AAIA,MAAM,WAAW,qBAAqB;IACpC,OAAO,EAAE,MAAM,CAAC;CACjB;AAQD,wBAAgB,gBAAgB,CAAC,EAAE,OAAO,EAAE,EAAE,qBAAqB,2CA0BlE"}
@@ -0,0 +1,28 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import { useMemo, useState, useEffect } from 'react';
3
+ import { Marked } from 'marked';
4
+ // Private instance avoids mutating the global marked singleton
5
+ const parser = new Marked({ gfm: true, breaks: true });
6
+ // Module-level cache for the DOMPurify instance (browser only)
7
+ let purifyInstance = null;
8
+ export function MarkdownRenderer({ content }) {
9
+ // Track whether DOMPurify has been loaded so useMemo re-runs after load
10
+ const [purifyReady, setPurifyReady] = useState(() => purifyInstance !== null);
11
+ useEffect(() => {
12
+ if (typeof window === 'undefined' || purifyInstance !== null)
13
+ return;
14
+ import('dompurify').then((mod) => {
15
+ purifyInstance = mod.default;
16
+ setPurifyReady(true);
17
+ }).catch(() => { });
18
+ }, []);
19
+ const html = useMemo(() => {
20
+ if (typeof window === 'undefined' || !purifyInstance)
21
+ return '';
22
+ const raw = parser.parse(content);
23
+ return purifyInstance.sanitize(raw, { ADD_ATTR: ['target'] });
24
+ // eslint-disable-next-line react-hooks/exhaustive-deps
25
+ }, [content, purifyReady]);
26
+ return (_jsx("div", { className: "t2v-md", dangerouslySetInnerHTML: { __html: html }, style: { fontSize: 'inherit', lineHeight: 1.55, wordBreak: 'break-word' } }));
27
+ }
28
+ //# sourceMappingURL=MarkdownRenderer.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"MarkdownRenderer.js","sourceRoot":"","sources":["../../../src/ui/components/MarkdownRenderer.tsx"],"names":[],"mappings":";AAAA,OAAc,EAAE,OAAO,EAAE,QAAQ,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAC5D,OAAO,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAOhC,+DAA+D;AAC/D,MAAM,MAAM,GAAG,IAAI,MAAM,CAAC,EAAE,GAAG,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC;AAEvD,+DAA+D;AAC/D,IAAI,cAAc,GAAgC,IAAI,CAAC;AAEvD,MAAM,UAAU,gBAAgB,CAAC,EAAE,OAAO,EAAyB;IACjE,wEAAwE;IACxE,MAAM,CAAC,WAAW,EAAE,cAAc,CAAC,GAAG,QAAQ,CAAC,GAAG,EAAE,CAAC,cAAc,KAAK,IAAI,CAAC,CAAC;IAE9E,SAAS,CAAC,GAAG,EAAE;QACb,IAAI,OAAO,MAAM,KAAK,WAAW,IAAI,cAAc,KAAK,IAAI;YAAE,OAAO;QACrE,MAAM,CAAC,WAAW,CAAC,CAAC,IAAI,CAAC,CAAC,GAAG,EAAE,EAAE;YAC/B,cAAc,GAAG,GAAG,CAAC,OAAO,CAAC;YAC7B,cAAc,CAAC,IAAI,CAAC,CAAC;QACvB,CAAC,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE,GAAE,CAAC,CAAC,CAAC;IACrB,CAAC,EAAE,EAAE,CAAC,CAAC;IAEP,MAAM,IAAI,GAAG,OAAO,CAAC,GAAG,EAAE;QACxB,IAAI,OAAO,MAAM,KAAK,WAAW,IAAI,CAAC,cAAc;YAAE,OAAO,EAAE,CAAC;QAChE,MAAM,GAAG,GAAG,MAAM,CAAC,KAAK,CAAC,OAAO,CAAW,CAAC;QAC5C,OAAO,cAAc,CAAC,QAAQ,CAAC,GAAG,EAAE,EAAE,QAAQ,EAAE,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC;QAChE,uDAAuD;IACvD,CAAC,EAAE,CAAC,OAAO,EAAE,WAAW,CAAC,CAAC,CAAC;IAE3B,OAAO,CACL,cACE,SAAS,EAAC,QAAQ,EAClB,uBAAuB,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,EACzC,KAAK,EAAE,EAAE,QAAQ,EAAE,SAAS,EAAE,UAAU,EAAE,IAAI,EAAE,SAAS,EAAE,YAAY,EAAE,GACzE,CACH,CAAC;AACJ,CAAC"}
@@ -0,0 +1,6 @@
1
+ export interface MessageActionsProps {
2
+ content: string;
3
+ isLast: boolean;
4
+ }
5
+ export declare function MessageActions({ content, isLast }: MessageActionsProps): import("react/jsx-runtime").JSX.Element;
6
+ //# sourceMappingURL=MessageActions.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"MessageActions.d.ts","sourceRoot":"","sources":["../../../src/ui/components/MessageActions.tsx"],"names":[],"mappings":"AAIA,MAAM,WAAW,mBAAmB;IAClC,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,OAAO,CAAC;CACjB;AAED,wBAAgB,cAAc,CAAC,EAAE,OAAO,EAAE,MAAM,EAAE,EAAE,mBAAmB,2CA6DtE"}
@@ -0,0 +1,43 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { useState, useEffect, useRef } from 'react';
3
+ import { Copy, Check, RefreshCw } from 'lucide-react';
4
+ import { useChat } from '../context';
5
+ export function MessageActions({ content, isLast }) {
6
+ const { retryLastMessage } = useChat();
7
+ const [copied, setCopied] = useState(false);
8
+ const timerRef = useRef(undefined);
9
+ // Clear timeout on unmount to prevent memory leak
10
+ useEffect(() => () => { clearTimeout(timerRef.current); }, []);
11
+ const handleCopy = () => {
12
+ navigator.clipboard.writeText(content).then(() => {
13
+ clearTimeout(timerRef.current);
14
+ setCopied(true);
15
+ timerRef.current = setTimeout(() => setCopied(false), 2000);
16
+ }).catch(() => {
17
+ // Fallback for insecure contexts (HTTP)
18
+ try {
19
+ const textarea = document.createElement('textarea');
20
+ textarea.value = content;
21
+ textarea.style.position = 'fixed';
22
+ textarea.style.opacity = '0';
23
+ document.body.appendChild(textarea);
24
+ textarea.select();
25
+ document.execCommand('copy');
26
+ document.body.removeChild(textarea);
27
+ clearTimeout(timerRef.current);
28
+ setCopied(true);
29
+ timerRef.current = setTimeout(() => setCopied(false), 2000);
30
+ }
31
+ catch { /* ignore */ }
32
+ });
33
+ };
34
+ const btnStyle = {
35
+ display: 'inline-flex', alignItems: 'center', justifyContent: 'center',
36
+ width: 28, height: 28, borderRadius: '6px',
37
+ border: 'none', background: 'transparent', cursor: 'pointer',
38
+ color: 'var(--t2v-muted)', fontSize: '14px',
39
+ transition: 'background 0.15s, color 0.15s',
40
+ };
41
+ return (_jsxs("div", { style: { display: 'flex', gap: '2px', marginTop: '4px', opacity: 0.6, transition: 'opacity 0.15s' }, onMouseEnter: (e) => { e.currentTarget.style.opacity = '1'; }, onMouseLeave: (e) => { e.currentTarget.style.opacity = '0.6'; }, children: [_jsx("button", { onClick: handleCopy, title: copied ? 'Copied!' : 'Copy message', style: { ...btnStyle, color: copied ? 'var(--t2v-accent)' : 'var(--t2v-muted)' }, onMouseEnter: (e) => { e.currentTarget.style.background = 'var(--t2v-surface-hover)'; }, onMouseLeave: (e) => { e.currentTarget.style.background = 'transparent'; }, children: copied ? _jsx(Check, { size: 14 }) : _jsx(Copy, { size: 14 }) }), isLast && (_jsx("button", { onClick: () => { retryLastMessage().catch(() => { }); }, title: "Regenerate response", style: btnStyle, onMouseEnter: (e) => { e.currentTarget.style.background = 'var(--t2v-surface-hover)'; }, onMouseLeave: (e) => { e.currentTarget.style.background = 'transparent'; }, children: _jsx(RefreshCw, { size: 14 }) }))] }));
42
+ }
43
+ //# sourceMappingURL=MessageActions.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"MessageActions.js","sourceRoot":"","sources":["../../../src/ui/components/MessageActions.tsx"],"names":[],"mappings":"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"}
@@ -0,0 +1,16 @@
1
+ /**
2
+ * MessageBubble — renders a single chat message.
3
+ *
4
+ * User messages: right-aligned dark bubble, plain text.
5
+ * Assistant messages: left-aligned with Talk2View logo avatar, renders
6
+ * ThinkingBlock (if plan exists), ToolDisplay (if steps exist),
7
+ * ApprovalCard (if pendingApproval and isStreaming), MarkdownRenderer
8
+ * (for content), and a blinking streaming cursor.
9
+ */
10
+ import type { DisplayMessage } from '../../types';
11
+ export interface MessageBubbleProps {
12
+ message: DisplayMessage;
13
+ isLast?: boolean;
14
+ }
15
+ export declare function MessageBubble({ message, isLast }: MessageBubbleProps): import("react/jsx-runtime").JSX.Element;
16
+ //# sourceMappingURL=MessageBubble.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"MessageBubble.d.ts","sourceRoot":"","sources":["../../../src/ui/components/MessageBubble.tsx"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAGH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAUlD,MAAM,WAAW,kBAAkB;IACjC,OAAO,EAAE,cAAc,CAAC;IACxB,MAAM,CAAC,EAAE,OAAO,CAAC;CAClB;AAED,wBAAgB,aAAa,CAAC,EAAE,OAAO,EAAE,MAAM,EAAE,EAAE,kBAAkB,2CAmIpE"}
@@ -0,0 +1,71 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { useChat } from '../context';
3
+ import { LOGOS } from '../theme';
4
+ import { MarkdownRenderer } from './MarkdownRenderer';
5
+ import { ThinkingBlock } from './ThinkingBlock';
6
+ import { ToolStepGroup } from './ToolDisplay';
7
+ import { ApprovalCard } from './ApprovalCard';
8
+ import { MessageActions } from './MessageActions';
9
+ import { Shimmer } from './Shimmer';
10
+ export function MessageBubble({ message, isLast }) {
11
+ const { pendingApproval, approveToolCall } = useChat();
12
+ const isUser = message.role === 'user';
13
+ if (isUser) {
14
+ return (_jsx("div", { style: {
15
+ display: 'flex',
16
+ justifyContent: 'flex-end',
17
+ marginBottom: '12px',
18
+ animation: 't2v-fade-in 0.2s ease-out',
19
+ }, children: _jsx("div", { style: {
20
+ maxWidth: '75%',
21
+ padding: '10px 14px',
22
+ borderRadius: 'calc(var(--t2v-radius) * 1px)',
23
+ borderBottomRightRadius: '4px',
24
+ background: 'var(--t2v-user-bubble)',
25
+ color: 'var(--t2v-user-foreground)',
26
+ fontSize: '14px',
27
+ lineHeight: 1.5,
28
+ fontFamily: 'var(--t2v-font)',
29
+ whiteSpace: 'pre-wrap',
30
+ wordBreak: 'break-word',
31
+ }, children: message.content }) }));
32
+ }
33
+ // Assistant message
34
+ const showApproval = message.isStreaming &&
35
+ pendingApproval !== null;
36
+ return (_jsxs("div", { style: {
37
+ display: 'flex',
38
+ alignItems: 'flex-start',
39
+ gap: '8px',
40
+ marginBottom: '12px',
41
+ animation: 't2v-fade-in 0.2s ease-out',
42
+ }, children: [_jsx("img", { src: LOGOS.icon, alt: "Talk2View", style: {
43
+ width: '24px',
44
+ height: '24px',
45
+ borderRadius: '50%',
46
+ flexShrink: 0,
47
+ marginTop: '2px',
48
+ objectFit: 'contain',
49
+ background: 'var(--t2v-bg)',
50
+ border: '1px solid var(--t2v-border)',
51
+ } }), _jsxs("div", { style: {
52
+ flex: 1,
53
+ minWidth: 0,
54
+ fontSize: '14px',
55
+ lineHeight: 1.55,
56
+ color: 'var(--t2v-foreground)',
57
+ fontFamily: 'var(--t2v-font)',
58
+ background: 'var(--t2v-surface)',
59
+ borderRadius: '8px',
60
+ padding: '10px 12px',
61
+ }, children: [message.plan && _jsx(ThinkingBlock, { content: message.plan }), message.steps && message.steps.length > 0 && (_jsx("div", { style: { marginBottom: message.content ? '8px' : '0' }, children: _jsx(ToolStepGroup, { steps: message.steps, isStreaming: message.isStreaming }) })), showApproval && pendingApproval && (_jsx(ApprovalCard, { toolName: pendingApproval.toolName, toolCallId: pendingApproval.toolCallId, args: pendingApproval.arguments, description: pendingApproval.description, onDecision: approveToolCall })), message.isStreaming && !message.content && !message.plan && !pendingApproval && (_jsx(Shimmer, {})), message.content && _jsx(MarkdownRenderer, { content: message.content }), message.isStreaming && message.content && !pendingApproval && !message.plan && (_jsx("span", { style: {
62
+ display: 'inline-block',
63
+ width: '2px',
64
+ height: '1em',
65
+ background: 'var(--t2v-accent)',
66
+ marginLeft: '2px',
67
+ verticalAlign: 'text-bottom',
68
+ animation: 't2v-blink 1s step-start infinite',
69
+ } })), !message.isStreaming && message.content && (_jsx(MessageActions, { content: message.content, isLast: isLast ?? false }))] })] }));
70
+ }
71
+ //# sourceMappingURL=MessageBubble.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"MessageBubble.js","sourceRoot":"","sources":["../../../src/ui/components/MessageBubble.tsx"],"names":[],"mappings":"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"}
@@ -0,0 +1,10 @@
1
+ /**
2
+ * MessageList — scrollable list of chat messages.
3
+ *
4
+ * - Auto-scrolls to bottom when messages change (only if already near bottom).
5
+ * - Shows a scroll-to-bottom button when scrolled up more than 150px.
6
+ * - Shows a Shimmer typing indicator when isLoading and last message has no content.
7
+ * - Renders a MessageBubble for each message.
8
+ */
9
+ export declare function MessageList(): import("react/jsx-runtime").JSX.Element;
10
+ //# sourceMappingURL=MessageList.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"MessageList.d.ts","sourceRoot":"","sources":["../../../src/ui/components/MessageList.tsx"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AASH,wBAAgB,WAAW,4CAwF1B"}
@@ -0,0 +1,69 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ /**
3
+ * MessageList — scrollable list of chat messages.
4
+ *
5
+ * - Auto-scrolls to bottom when messages change (only if already near bottom).
6
+ * - Shows a scroll-to-bottom button when scrolled up more than 150px.
7
+ * - Shows a Shimmer typing indicator when isLoading and last message has no content.
8
+ * - Renders a MessageBubble for each message.
9
+ */
10
+ import { useCallback, useEffect, useRef, useState } from 'react';
11
+ import { ArrowDown } from 'lucide-react';
12
+ import { useChat } from '../context';
13
+ import { MessageBubble } from './MessageBubble';
14
+ export function MessageList() {
15
+ const { messages, isLoading } = useChat();
16
+ const containerRef = useRef(null);
17
+ const [showScrollBtn, setShowScrollBtn] = useState(false);
18
+ const isNearBottom = useCallback(() => {
19
+ const el = containerRef.current;
20
+ if (!el)
21
+ return true;
22
+ return el.scrollHeight - el.scrollTop - el.clientHeight < 150;
23
+ }, []);
24
+ const scrollToBottom = useCallback((behavior = 'smooth') => {
25
+ const el = containerRef.current;
26
+ if (!el)
27
+ return;
28
+ el.scrollTo({ top: el.scrollHeight, behavior });
29
+ }, []);
30
+ // Auto-scroll when messages change (only if already near bottom)
31
+ useEffect(() => {
32
+ if (isNearBottom()) {
33
+ scrollToBottom('smooth');
34
+ }
35
+ }, [messages, isNearBottom, scrollToBottom]);
36
+ // Track scroll position to show/hide scroll-to-bottom button
37
+ const handleScroll = useCallback(() => {
38
+ const el = containerRef.current;
39
+ if (!el)
40
+ return;
41
+ const distanceFromBottom = el.scrollHeight - el.scrollTop - el.clientHeight;
42
+ setShowScrollBtn(distanceFromBottom > 150);
43
+ }, []);
44
+ return (_jsxs("div", { style: { position: 'relative', flex: 1, minHeight: 0 }, children: [_jsxs("div", { ref: containerRef, role: "log", "aria-live": "polite", className: "t2v-scrollable", onScroll: handleScroll, style: {
45
+ height: '100%',
46
+ overflowY: 'auto',
47
+ padding: '16px',
48
+ boxSizing: 'border-box',
49
+ }, children: [messages.map((msg, i) => (_jsx(MessageBubble, { message: msg, isLast: i === messages.length - 1 }, msg.id))), _jsx("div", { style: { height: showScrollBtn ? '40px' : '0' } })] }), showScrollBtn && (_jsxs("button", { onClick: () => scrollToBottom('smooth'), "aria-label": "Scroll to bottom", style: {
50
+ position: 'absolute',
51
+ bottom: '16px',
52
+ left: '50%',
53
+ transform: 'translateX(-50%)',
54
+ display: 'flex',
55
+ alignItems: 'center',
56
+ gap: '4px',
57
+ padding: '6px 12px',
58
+ background: 'var(--t2v-bg)',
59
+ border: '1px solid var(--t2v-border)',
60
+ borderRadius: '16px',
61
+ cursor: 'pointer',
62
+ fontSize: '12px',
63
+ fontFamily: 'var(--t2v-font)',
64
+ color: 'var(--t2v-muted)',
65
+ boxShadow: '0 2px 8px rgba(0,0,0,0.08)',
66
+ zIndex: 1,
67
+ }, children: [_jsx(ArrowDown, { size: 14 }), "Scroll to bottom"] }))] }));
68
+ }
69
+ //# sourceMappingURL=MessageList.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"MessageList.js","sourceRoot":"","sources":["../../../src/ui/components/MessageList.tsx"],"names":[],"mappings":"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"}
@@ -0,0 +1,11 @@
1
+ /**
2
+ * SettingsPanel — full-panel settings page for user preferences.
3
+ */
4
+ export interface SettingsPanelProps {
5
+ onBack?: () => void;
6
+ onModelChange?: (model: string) => void;
7
+ /** Hide the built-in header (use when embedding in a container with its own header). */
8
+ hideHeader?: boolean;
9
+ }
10
+ export declare function SettingsPanel({ onBack, onModelChange, hideHeader }: SettingsPanelProps): import("react/jsx-runtime").JSX.Element;
11
+ //# sourceMappingURL=SettingsPanel.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"SettingsPanel.d.ts","sourceRoot":"","sources":["../../../src/ui/components/SettingsPanel.tsx"],"names":[],"mappings":"AAAA;;GAEG;AASH,MAAM,WAAW,kBAAkB;IACjC,MAAM,CAAC,EAAE,MAAM,IAAI,CAAC;IACpB,aAAa,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IACxC,wFAAwF;IACxF,UAAU,CAAC,EAAE,OAAO,CAAC;CACtB;AAuDD,wBAAgB,aAAa,CAAC,EAAE,MAAM,EAAE,aAAa,EAAE,UAAU,EAAE,EAAE,kBAAkB,2CAyPtF"}