@trtc/calls-uikit-react 4.4.3 → 4.4.4

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 (53) hide show
  1. package/package.json +2 -2
  2. package/src/Components/assets/aiAssistant/desktop/subtitleSettings.svg +4 -0
  3. package/src/Components/assets/aiAssistant/mobile/close-aiAssistant.svg +7 -0
  4. package/src/Components/assets/aiAssistant/mobile/open-aiAssistant.svg +7 -0
  5. package/src/Components/assets/aiAssistant/mobile/subtitleSettings.svg +3 -0
  6. package/src/Components/components/base/CustomSelect/CustomSelect.scss +116 -0
  7. package/src/Components/components/base/CustomSelect/CustomSelect.tsx +96 -0
  8. package/src/Components/components/common/AIAssistant/AISubtitle.scss +109 -0
  9. package/src/Components/components/common/AIAssistant/AISubtitle.tsx +52 -66
  10. package/src/Components/components/common/AIAssistant/components/AITranscriberSwitchH5.tsx +39 -0
  11. package/src/Components/components/common/AIAssistant/components/AITranscriberSwitchPC.scss +46 -0
  12. package/src/Components/components/common/AIAssistant/components/AITranscriberSwitchPC.tsx +42 -0
  13. package/src/Components/components/common/AIAssistant/components/SubtitleContent.scss +67 -0
  14. package/src/Components/components/common/AIAssistant/components/SubtitleContent.tsx +134 -0
  15. package/src/Components/components/common/AIAssistant/components/SubtitleSettingsH5.scss +275 -0
  16. package/src/Components/components/common/AIAssistant/components/SubtitleSettingsH5.tsx +265 -0
  17. package/src/Components/components/common/AIAssistant/components/SubtitleSettingsPC.scss +98 -0
  18. package/src/Components/components/common/AIAssistant/components/SubtitleSettingsPC.tsx +198 -0
  19. package/src/Components/components/common/AIAssistant/components/index.ts +5 -0
  20. package/src/Components/components/common/AIAssistant/index.ts +3 -1
  21. package/src/Components/components/common/TopBar/h5/TopBarH5.tsx +11 -1
  22. package/src/Components/components/common/TopBar/pc/TopBarPC.module.scss +20 -0
  23. package/src/Components/components/common/TopBar/pc/TopBarPC.tsx +14 -9
  24. package/src/Components/hooks/index.ts +2 -0
  25. package/src/Components/hooks/useAIAssistant.ts +174 -0
  26. package/src/TUICallService/CallService/AIAssistant.ts +285 -39
  27. package/src/TUICallService/CallService/index.ts +19 -9
  28. package/src/TUICallService/TUIStore/callStore.ts +5 -0
  29. package/src/TUICallService/const/index.ts +4 -0
  30. package/src/TUICallService/interface/ICallStore.ts +5 -0
  31. package/src/TUICallService/locales/en.ts +15 -0
  32. package/src/TUICallService/locales/ja_JP.ts +15 -0
  33. package/src/TUICallService/locales/zh-cn.ts +15 -0
  34. package/src/index.ts +1 -1
  35. package/tuicall-uikit-react.es.js +4265 -3703
  36. package/tuicall-uikit-react.umd.js +8 -3
  37. package/types/Components/components/base/CustomSelect/CustomSelect.d.ts +15 -0
  38. package/types/Components/components/common/AIAssistant/AISubtitle.d.ts +1 -0
  39. package/types/Components/components/common/AIAssistant/components/AITranscriberSwitchH5.d.ts +3 -0
  40. package/types/Components/components/common/AIAssistant/components/AITranscriberSwitchPC.d.ts +4 -0
  41. package/types/Components/components/common/AIAssistant/components/SubtitleContent.d.ts +8 -0
  42. package/types/Components/components/common/AIAssistant/components/SubtitleSettingsH5.d.ts +13 -0
  43. package/types/Components/components/common/AIAssistant/components/SubtitleSettingsPC.d.ts +13 -0
  44. package/types/Components/components/common/AIAssistant/components/index.d.ts +5 -0
  45. package/types/Components/components/common/AIAssistant/index.d.ts +1 -0
  46. package/types/Components/hooks/index.d.ts +2 -1
  47. package/types/Components/hooks/useAIAssistant.d.ts +22 -0
  48. package/types/TUICallService/CallService/AIAssistant.d.ts +72 -15
  49. package/types/TUICallService/CallService/index.d.ts +2 -1
  50. package/types/TUICallService/interface/ICallStore.d.ts +4 -0
  51. package/types/TUICallService/locales/en.d.ts +14 -0
  52. package/types/TUICallService/locales/ja_JP.d.ts +14 -0
  53. package/types/TUICallService/locales/zh-cn.d.ts +14 -0
@@ -0,0 +1,67 @@
1
+ // Common styles for both PC and H5
2
+ .subtitle-content {
3
+ position: relative;
4
+ padding: 10px 12px;
5
+ color: #fff;
6
+ background-color: #000000B8;
7
+ opacity: 0.72;
8
+ border-radius: 8px;
9
+ overflow-y: auto;
10
+ overflow-x: hidden;
11
+ bottom: 10px;
12
+ font-size: 12px;
13
+
14
+ /* Hide scrollbar for webkit browsers */
15
+ &::-webkit-scrollbar {
16
+ width: 0;
17
+ background: transparent;
18
+ }
19
+
20
+ /* Hide scrollbar for Firefox */
21
+ scrollbar-width: none;
22
+ }
23
+
24
+ // PC specific styles
25
+ .subtitle-content:not(.subtitle-content--h5) {
26
+ width: 640px;
27
+ min-width: 640px;
28
+ height: 180px;
29
+ max-height: 180px;
30
+
31
+ .subtitle-content__settings-btn {
32
+ position: fixed;
33
+ top: 6px;
34
+ right: 6px;
35
+ cursor: pointer;
36
+ z-index: 999;
37
+ }
38
+ }
39
+
40
+ // H5 specific styles
41
+ .subtitle-content--h5 {
42
+ position: relative;
43
+ width: 350px;
44
+ min-width: 350px;
45
+ height: 116px;
46
+ max-height: 116px;
47
+ bottom: 24px;
48
+
49
+ .subtitle-content__settings-btn {
50
+ position: fixed;
51
+ top: 30%;
52
+ right: 4px;
53
+ cursor: pointer;
54
+ z-index: 999;
55
+ transform: translateY(-50%);
56
+ }
57
+ }
58
+
59
+ .sender-name {
60
+ font-family: PingFang SC;
61
+ font-weight: 400;
62
+ font-style: normal;
63
+ font-size: 12px;
64
+ line-height: 16px;
65
+ letter-spacing: 0px;
66
+ color: #FFFFFFBF;
67
+ }
@@ -0,0 +1,134 @@
1
+ import React, { useState, useRef, useEffect } from 'react';
2
+ import { TUIGlobal } from '../../../../../TUICallService/index';
3
+ import { useAIAssistant } from '../../../../hooks/useAIAssistant';
4
+ import subtitleSettingsDeskTopIcon from '../../../../assets/aiAssistant/desktop/subtitleSettings.svg';
5
+ import subtitleSettingsH5Icon from '../../../../assets/aiAssistant/mobile/subtitleSettings.svg';
6
+ import './SubtitleContent.scss';
7
+
8
+ interface SubtitleContentProps {
9
+ onOpenSettings: () => void;
10
+ className?: string;
11
+ }
12
+
13
+ interface ITranslationContent {
14
+ language: string;
15
+ text: string;
16
+ }
17
+
18
+ interface ITranslationInfo {
19
+ roundId: string;
20
+ sender: string;
21
+ nick?: string;
22
+ text: string;
23
+ end: boolean;
24
+ translation: ITranslationContent[];
25
+ }
26
+
27
+ const SubtitleContent: React.FC<SubtitleContentProps> = ({ onOpenSettings, className }) => {
28
+ // Internal state management
29
+ const [showSettingsIcon, setShowSettingsIcon] = useState(false);
30
+ const subtitleContainerRef = useRef<HTMLDivElement | null>(null);
31
+
32
+ // Use AI Assistant hook (combines both status and subtitle data)
33
+ const { subtitleInfoList, isAITranscriberRunning } = useAIAssistant();
34
+
35
+ // Device type detection
36
+ const isH5 = !TUIGlobal.isPC;
37
+
38
+ // Dynamic icon selection based on device type
39
+ const settingsIcon = isH5 ? subtitleSettingsH5Icon : subtitleSettingsDeskTopIcon;
40
+ const iconSize = isH5 ? 24 : 20;
41
+
42
+ // Parse translation data to extract language and text
43
+ const parseTranslationData = (content: any) => {
44
+ if (content === null || content === undefined) {
45
+ return { language: 'Unknown', text: '' };
46
+ }
47
+
48
+ // If content is already a string, check if it's a JSON string
49
+ if (typeof content === 'string') {
50
+ try {
51
+ // Try to parse as JSON in case it's a nested JSON string
52
+ const parsed = JSON.parse(content);
53
+ if (parsed && typeof parsed === 'object') {
54
+ return {
55
+ language: parsed.language || 'Unknown',
56
+ text: parsed.text || content
57
+ };
58
+ }
59
+ return { language: 'Unknown', text: content };
60
+ } catch {
61
+ // If parsing fails, return the original string
62
+ return { language: 'Unknown', text: content };
63
+ }
64
+ }
65
+
66
+ return { language: 'Unknown', text: String(content) };
67
+ };
68
+
69
+ // Format translation content to prevent [object Object] display
70
+ const formatTranslationContent = (content: any): string => {
71
+ return parseTranslationData(content).text;
72
+ };
73
+
74
+ // Auto-scroll to bottom when new messages arrive
75
+ useEffect(() => {
76
+ if (subtitleContainerRef.current) {
77
+ subtitleContainerRef.current.scrollTop = subtitleContainerRef.current.scrollHeight;
78
+ }
79
+ }, [subtitleInfoList]);
80
+
81
+ // Don't render if transcriber is not running or no subtitles
82
+ if (!isAITranscriberRunning || !Array.isArray(subtitleInfoList) || subtitleInfoList.length === 0) {
83
+ return null;
84
+ }
85
+
86
+ const handleMouseEnter = () => {
87
+ if (!isH5) {
88
+ setShowSettingsIcon(true);
89
+ }
90
+ };
91
+
92
+ const handleMouseLeave = () => {
93
+ if (!isH5) {
94
+ setShowSettingsIcon(false);
95
+ }
96
+ };
97
+
98
+ return (
99
+ <div
100
+ ref={subtitleContainerRef}
101
+ className={`subtitle-content ${isH5 ? 'subtitle-content--h5' : ''} ${className || ''}`}
102
+ onMouseEnter={handleMouseEnter}
103
+ onMouseLeave={handleMouseLeave}
104
+ >
105
+ <div
106
+ className={`subtitle-content__settings-btn ${isH5 ? 'subtitle-content__settings-btn--h5' : ''}`}
107
+ style={{ display: isH5 || showSettingsIcon ? 'block' : 'none' }}
108
+ onClick={onOpenSettings}
109
+ >
110
+ <img
111
+ src={settingsIcon}
112
+ width={iconSize}
113
+ height={iconSize}
114
+ alt="Settings"
115
+ />
116
+ </div>
117
+
118
+ {subtitleInfoList.map((subtitleInfo: ITranslationInfo, index: number) => (
119
+ <div key={subtitleInfo.roundId}>
120
+ {index !== 0 && <div style={{ height: '16px' }} />}
121
+ <div className="sender-name">{`${subtitleInfo?.nick || subtitleInfo?.sender}:`}</div>
122
+ <div>{subtitleInfo?.text}</div>
123
+ {Array.isArray(subtitleInfo?.translation) && subtitleInfo.translation.map((translationContent: ITranslationContent, transIndex: number) => (
124
+ <div key={transIndex}>
125
+ <span>{formatTranslationContent(translationContent?.text)}</span>
126
+ </div>
127
+ ))}
128
+ </div>
129
+ ))}
130
+ </div>
131
+ );
132
+ };
133
+
134
+ export default SubtitleContent;
@@ -0,0 +1,275 @@
1
+ .subtitle-settings-overlay {
2
+ position: fixed;
3
+ top: 0;
4
+ left: 0;
5
+ right: 0;
6
+ bottom: 0;
7
+ width: 100vw;
8
+ height: 100vh;
9
+ background-color: rgba(0, 0, 0, 0.5);
10
+ z-index: 1000;
11
+ display: flex;
12
+ align-items: center;
13
+ justify-content: center;
14
+ font-family: PingFang SC;
15
+ }
16
+
17
+ .subtitle-settings-modal {
18
+ background-color: white;
19
+ border-radius: 12px;
20
+ width: 90%;
21
+ max-width: 400px;
22
+ max-height: 80vh;
23
+ display: flex;
24
+ flex-direction: column;
25
+ overflow: hidden;
26
+ animation: modalSlideIn 0.3s ease-out;
27
+ }
28
+
29
+ @keyframes modalSlideIn {
30
+ from {
31
+ opacity: 0;
32
+ transform: scale(0.9) translateY(-20px);
33
+ }
34
+ to {
35
+ opacity: 1;
36
+ transform: scale(1) translateY(0);
37
+ }
38
+ }
39
+
40
+ .modal-header {
41
+ text-align: center;
42
+ padding: 20px 20px 16px;
43
+ }
44
+
45
+ .modal-title {
46
+ font-size: 18px;
47
+ font-weight: 500;
48
+ color: #333;
49
+ margin: 0;
50
+ }
51
+
52
+ .modal-content {
53
+ flex: 1;
54
+ overflow-y: auto;
55
+ padding: 16px 0;
56
+ }
57
+
58
+ .modal-footer {
59
+ display: flex;
60
+ gap: 12px;
61
+ padding: 16px 20px 20px;
62
+ }
63
+
64
+ .btn {
65
+ flex: 1;
66
+ height: 44px;
67
+ border-radius: 10px;
68
+ border: none;
69
+ font-size: 16px;
70
+ font-weight: 500;
71
+ cursor: pointer;
72
+ transition: all 0.2s;
73
+
74
+ &.btn-cancel {
75
+ color: #1C66E5;
76
+ border: 1px solid #1C66E5;
77
+ background-color: white;
78
+ }
79
+
80
+ &.btn-confirm {
81
+ background-color: #1677ff;
82
+ color: white;
83
+ }
84
+ }
85
+
86
+ .setting-group {
87
+ margin-bottom: 12px;
88
+
89
+ &:last-child {
90
+ margin-bottom: 0;
91
+ }
92
+ }
93
+
94
+ .group-title {
95
+ font-size: 13px;
96
+ color: #666;
97
+ padding: 0 20px 8px;
98
+ margin-bottom: 2px;
99
+ }
100
+
101
+ .group-content {
102
+ background: white;
103
+ border-radius: 8px;
104
+ margin: 0 16px;
105
+ overflow: hidden;
106
+ border: 1px solid #f0f0f0;
107
+ }
108
+
109
+ .setting-section {
110
+ border-bottom: 1px solid #f0f0f0;
111
+
112
+ &:last-child {
113
+ border-bottom: none;
114
+ }
115
+ }
116
+
117
+ .section-header {
118
+ display: flex;
119
+ align-items: center;
120
+ justify-content: space-between;
121
+ padding: 16px;
122
+ cursor: pointer;
123
+ transition: background-color 0.2s;
124
+
125
+ &:active {
126
+ background-color: #f8f8f8;
127
+ }
128
+ }
129
+
130
+ .section-title {
131
+ font-size: 16px;
132
+ color: #333;
133
+ font-weight: 400;
134
+ }
135
+
136
+ .section-value {
137
+ display: flex;
138
+ align-items: center;
139
+ font-size: 14px;
140
+ color: #666;
141
+ gap: 4px;
142
+ }
143
+
144
+ .arrow-icon {
145
+ flex-shrink: 0;
146
+ }
147
+
148
+ .toggle-switch {
149
+ width: 44px;
150
+ height: 24px;
151
+ background-color: #ccc;
152
+ border-radius: 12px;
153
+ position: relative;
154
+ cursor: pointer;
155
+ transition: background-color 0.3s;
156
+
157
+ &.active {
158
+ background-color: #1677ff;
159
+ }
160
+ }
161
+
162
+ .toggle-slider {
163
+ width: 20px;
164
+ height: 20px;
165
+ background-color: white;
166
+ border-radius: 50%;
167
+ position: absolute;
168
+ top: 2px;
169
+ left: 2px;
170
+ transition: transform 0.3s;
171
+ box-shadow: 0 2px 4px rgba(0, 0, 0, 0.2);
172
+
173
+ .toggle-switch.active & {
174
+ transform: translateX(20px);
175
+ }
176
+ }
177
+
178
+ // Language Selector Styles
179
+ .language-selector-overlay {
180
+ position: fixed;
181
+ top: 0;
182
+ left: 0;
183
+ right: 0;
184
+ bottom: 0;
185
+ width: 100%;
186
+ height: 100vh;
187
+ background-color: rgba(0, 0, 0, 0.5);
188
+ z-index: 1100;
189
+ display: flex;
190
+ flex-direction: column;
191
+ justify-content: flex-end;
192
+ overflow: hidden;
193
+ }
194
+
195
+ .language-selector {
196
+ max-height: 70vh;
197
+ display: flex;
198
+ flex-direction: column;
199
+ background-color: white;
200
+ border-radius: 16px 16px 0 0;
201
+ padding-bottom: env(safe-area-inset-bottom);
202
+ transform: translateY(0);
203
+ animation: slideUp 0.3s ease-out;
204
+ }
205
+
206
+ @keyframes slideUp {
207
+ from {
208
+ transform: translateY(100%);
209
+ }
210
+ to {
211
+ transform: translateY(0);
212
+ }
213
+ }
214
+
215
+ .selector-header {
216
+ text-align: center;
217
+ padding: 16px 16px 12px;
218
+ border-bottom: 1px solid #e5e5e5;
219
+ background: white;
220
+ border-radius: 16px 16px 0 0;
221
+ }
222
+
223
+ .selector-title {
224
+ font-size: 12px;
225
+ font-weight: 400;
226
+ color: #00000066;
227
+ margin: 0;
228
+ }
229
+
230
+ .language-list {
231
+ flex: 1;
232
+ overflow-y: auto;
233
+ padding: 0 16px 16px;
234
+ max-height: 50vh;
235
+ }
236
+
237
+ .language-item {
238
+ font-family: PingFang SC;
239
+ font-weight: 400;
240
+ font-style: Regular;
241
+ font-size: 16px;
242
+ leading-trim: NONE;
243
+ line-height: 100%;
244
+ letter-spacing: 0px;
245
+ text-align: center;
246
+ text-transform: capitalize;
247
+ display: flex;
248
+ align-items: center;
249
+ justify-content: center;
250
+ padding: 16px 0;
251
+ border-bottom: 1px solid #f0f0f0;
252
+ cursor: pointer;
253
+ transition: background-color 0.2s;
254
+
255
+ &:active {
256
+ background-color: #f8f8f8;
257
+ }
258
+
259
+ &.selected {
260
+ color: #1677ff;
261
+ }
262
+
263
+ span {
264
+ font-size: 16px;
265
+ color: inherit;
266
+ }
267
+
268
+ &:last-child {
269
+ border-bottom: none;
270
+ }
271
+ }
272
+
273
+ .check-icon {
274
+ flex-shrink: 0;
275
+ }