tuikit-atomicx-vue3 3.3.1 → 3.3.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.
Files changed (48) hide show
  1. package/dist/components/ChatSetting/GroupChatSetting/GroupActions/GroupActions.js +1 -4
  2. package/dist/components/ChatSetting/GroupChatSetting/GroupChatSetting.js +1 -2
  3. package/dist/components/ChatSetting/GroupChatSetting/GroupManagement/GroupManagement.js +1 -2
  4. package/dist/components/CoGuestPanel/CoGuestPanel.js +6 -6
  5. package/dist/components/ContactList/ContactInfo/GroupInfo/GroupInfo.js +1 -2
  6. package/dist/components/ConversationList/ConversationCreate/ConversationCreate.js +1 -2
  7. package/dist/components/ConversationList/ConversationSearch/ConversationSearch.js +0 -1
  8. package/dist/components/LiveCoreView/PlayerControl/AudioControl.js +252 -0
  9. package/dist/components/LiveCoreView/PlayerControl/AudioControl.vue.d.ts +38 -0
  10. package/dist/components/LiveCoreView/PlayerControl/PlayerControl.js +279 -0
  11. package/dist/components/LiveCoreView/PlayerControl/PlayerControl.vue.d.ts +15 -0
  12. package/dist/components/LiveCoreView/PlayerControl/PlayerControlState.d.ts +29 -0
  13. package/dist/components/LiveCoreView/PlayerControl/PlayerControlState.js +412 -0
  14. package/dist/components/LiveCoreView/PlayerControl/index.d.ts +3 -0
  15. package/dist/components/LiveCoreView/PlayerControl/index.js +8 -0
  16. package/dist/components/LiveCoreView/PlayerControl/utils/deviceDetection.d.ts +85 -0
  17. package/dist/components/LiveCoreView/PlayerControl/utils/deviceDetection.js +129 -0
  18. package/dist/components/LiveCoreView/PlayerControl/utils/domHelpers.d.ts +75 -0
  19. package/dist/components/LiveCoreView/PlayerControl/utils/domHelpers.js +120 -0
  20. package/dist/components/LiveCoreView/PlayerControl/utils/fullscreenManager.d.ts +120 -0
  21. package/dist/components/LiveCoreView/PlayerControl/utils/fullscreenManager.js +311 -0
  22. package/dist/components/LiveCoreView/i18n/en-US/index.d.ts +9 -0
  23. package/dist/components/LiveCoreView/i18n/en-US/index.js +10 -1
  24. package/dist/components/LiveCoreView/i18n/zh-CN/index.d.ts +9 -0
  25. package/dist/components/LiveCoreView/i18n/zh-CN/index.js +10 -1
  26. package/dist/components/LiveCoreView/index.js +30 -4
  27. package/dist/components/StreamView/Layout/CustomLayout.js +2 -2
  28. package/dist/components/StreamView/Layout/GridLayout.js +2 -2
  29. package/dist/components/StreamView/common/StreamList/index.js +2 -2
  30. package/dist/styles/index.css +336 -31
  31. package/package.json +3 -3
  32. package/src/components/ChatSetting/GroupChatSetting/GroupActions/GroupActions.vue +0 -3
  33. package/src/components/ChatSetting/GroupChatSetting/GroupChatSetting.vue +0 -1
  34. package/src/components/ChatSetting/GroupChatSetting/GroupManagement/GroupManagement.vue +0 -1
  35. package/src/components/ContactList/ContactInfo/GroupInfo/GroupInfo.vue +0 -1
  36. package/src/components/ConversationList/ConversationCreate/ConversationCreate.vue +0 -1
  37. package/src/components/ConversationList/ConversationSearch/ConversationSearch.vue +0 -1
  38. package/src/components/LiveCoreView/PlayerControl/AudioControl.vue +434 -0
  39. package/src/components/LiveCoreView/PlayerControl/PlayerControl.module.scss +52 -0
  40. package/src/components/LiveCoreView/PlayerControl/PlayerControl.vue +484 -0
  41. package/src/components/LiveCoreView/PlayerControl/PlayerControlState.ts +602 -0
  42. package/src/components/LiveCoreView/PlayerControl/index.ts +3 -0
  43. package/src/components/LiveCoreView/PlayerControl/utils/deviceDetection.ts +234 -0
  44. package/src/components/LiveCoreView/PlayerControl/utils/domHelpers.ts +145 -0
  45. package/src/components/LiveCoreView/PlayerControl/utils/fullscreenManager.ts +417 -0
  46. package/src/components/LiveCoreView/i18n/en-US/index.ts +9 -0
  47. package/src/components/LiveCoreView/i18n/zh-CN/index.ts +9 -0
  48. package/src/components/LiveCoreView/index.vue +14 -3
@@ -63,7 +63,6 @@
63
63
 
64
64
  <!-- User Picker Dialog -->
65
65
  <TUIDialog
66
- appendTo="body"
67
66
  :custom-classes="['user-picker-dialog']"
68
67
  :visible="isShowUserPickerDialog"
69
68
  :title="userPickerTitle"
@@ -54,7 +54,6 @@
54
54
  {{ t('TUIContact.Enter group chat') }}
55
55
  </TUIButton>
56
56
  <TUIDialog
57
- appendTo="body"
58
57
  :visible="visible"
59
58
  :title="canDismissGroup ? t('TUIContact.Confirm dismiss group'): t('TUIContact.Confirm quit group')"
60
59
  :confirm-text="t('TUIContact.Submit')"
@@ -5,7 +5,6 @@
5
5
  <ConversationCreateButton @click="openCreateConversation" />
6
6
 
7
7
  <TUIDialog
8
- appendTo="body"
9
8
  :visible="showCreateConversation"
10
9
  :title="dialogTitles"
11
10
  :confirm-text="dialogConfirmText"
@@ -37,7 +37,6 @@
37
37
  </div>
38
38
 
39
39
  <TUIDialog
40
- appendTo="body"
41
40
  :customClasses="[$style.conversationSearch__advanced]"
42
41
  :visible="isShowStandard"
43
42
  :show-close="false"
@@ -0,0 +1,434 @@
1
+ <template>
2
+ <div class="audio-control" :style="iconSizeStyle" @mouseenter="handleMouseEnter" @mouseleave="handleMouseLeave">
3
+ <span class="control-btn volume-btn" :title="isMuted ? t('Unmute') : t('Mute')" @click="handleVolumeIconClick">
4
+ <IconSpeakerOff size="20" v-if="isMuted" />
5
+ <IconSpeakerOn size="20" v-else />
6
+ </span>
7
+ <div v-show="isVolumeSliderVisible" class="volume-slider-container">
8
+ <div
9
+ class="volume-slider-wrapper"
10
+ @mouseenter="handleVolumeSliderMouseEnter"
11
+ @mouseleave="handleVolumeSliderMouseLeave"
12
+ >
13
+ <div class="volume-slider-wrapper-inner">
14
+ <div
15
+ ref="volumeSliderElement"
16
+ class="custom-volume-slider"
17
+ @mousedown="handleSliderMouseDown"
18
+ @touchstart="handleSliderTouchStart"
19
+ @click="handleVolumeSliderAreaClick"
20
+ >
21
+ <div class="slider-track">
22
+ <div class="slider-progress" :style="{ height: `${volumePercentage}%` }"></div>
23
+ <div
24
+ class="slider-thumb"
25
+ :class="{ 'no-transition': isDragging }"
26
+ :style="{ bottom: `${volumePercentage}%` }"
27
+ ></div>
28
+ </div>
29
+ </div>
30
+ </div>
31
+ <div class="volume-value">{{ volumePercentage }}</div>
32
+ </div>
33
+ </div>
34
+ </div>
35
+ </template>
36
+
37
+ <script setup lang="ts">
38
+ import { computed, ref, onUnmounted, toRaw } from 'vue';
39
+ import { IconSpeakerOn, IconSpeakerOff, useUIKit } from '@tencentcloud/uikit-base-component-vue3';
40
+ import { isMobile } from '../../../utils';
41
+
42
+ interface AudioControlEmits {
43
+ (e: 'volume-change', value: number): void;
44
+ (e: 'muted-change', value: boolean): void;
45
+ }
46
+
47
+ interface AudioControlProps {
48
+ iconSize?: number;
49
+ enableVolumeControl?: boolean;
50
+ }
51
+
52
+ const props = withDefaults(defineProps<AudioControlProps>(), {
53
+ iconSize: 20,
54
+ enableVolumeControl: true,
55
+ });
56
+
57
+ const emit = defineEmits<AudioControlEmits>();
58
+
59
+ const { t } = useUIKit();
60
+
61
+ // Volume state - merged into single object
62
+ const volumeState = ref({
63
+ current: 1,
64
+ previous: 1,
65
+ });
66
+
67
+ const isMuted = ref(false);
68
+ const isVolumeSliderVisible = ref(false);
69
+ const isDragging = ref(false);
70
+ const volumeSliderElement = ref<HTMLElement>();
71
+ const volumeSliderAutoHideTimer = ref<number | null>(null);
72
+
73
+ // Auto-hide delay for different platforms
74
+ const AUTO_HIDE_DELAY = {
75
+ PC: 500, // 0.5 seconds for PC
76
+ MOBILE: 3000, // 3 seconds for mobile
77
+ };
78
+
79
+ // Simplified computed property - directly use isVolumeSliderVisible
80
+ const volumePercentage = computed(() => {
81
+ if (props.enableVolumeControl === false) {
82
+ return isMuted.value ? 0 : 100;
83
+ }
84
+ return Math.round(volumeState.value.current * 100);
85
+ });
86
+
87
+ const iconSizeStyle = computed(() => ({
88
+ width: `${props.iconSize || 20}px`,
89
+ height: `${props.iconSize || 20}px`,
90
+ }));
91
+
92
+ const updateVolume = (newVolume: number) => {
93
+ volumeState.value.previous = toRaw(volumeState.value.current);
94
+ volumeState.value.current = newVolume;
95
+ isMuted.value = newVolume === 0;
96
+ emit('volume-change', newVolume);
97
+ };
98
+
99
+ const toggleMute = () => {
100
+ if (isMuted.value) {
101
+ isMuted.value = false;
102
+ volumeState.value.current = volumeState.value.previous || 0.2;
103
+ emit('muted-change', false);
104
+ emit('volume-change', volumeState.value.current);
105
+ } else {
106
+ isMuted.value = true;
107
+ volumeState.value.previous = volumeState.value.current;
108
+ volumeState.value.current = 0;
109
+ emit('muted-change', true);
110
+ emit('volume-change', volumeState.value.current);
111
+ }
112
+ };
113
+
114
+ const handleVolumeIconClick = () => {
115
+ if (props.enableVolumeControl === false) {
116
+ // When volume control is disabled, handle mute/unmute on all platforms
117
+ toggleMute();
118
+ } else {
119
+ // When volume control is enabled
120
+ if (isMobile) {
121
+ // On mobile: toggle volume slider visibility
122
+ isVolumeSliderVisible.value = !isVolumeSliderVisible.value;
123
+
124
+ // Start auto-hide timer when showing volume slider
125
+ if (isVolumeSliderVisible.value) {
126
+ startVolumeSliderAutoHideTimer();
127
+ } else {
128
+ stopVolumeSliderAutoHideTimer();
129
+ }
130
+ } else {
131
+ // On PC: handle mute/unmute, volume slider will show on mouse hover
132
+ toggleMute();
133
+ }
134
+ }
135
+ };
136
+
137
+ const startVolumeSliderAutoHideTimer = () => {
138
+ stopVolumeSliderAutoHideTimer();
139
+ const delay = isMobile ? AUTO_HIDE_DELAY.MOBILE : AUTO_HIDE_DELAY.PC;
140
+ volumeSliderAutoHideTimer.value = window.setTimeout(() => {
141
+ if (props.enableVolumeControl) {
142
+ isVolumeSliderVisible.value = false;
143
+ }
144
+ }, delay);
145
+ };
146
+
147
+ const stopVolumeSliderAutoHideTimer = () => {
148
+ if (volumeSliderAutoHideTimer.value) {
149
+ clearTimeout(volumeSliderAutoHideTimer.value);
150
+ volumeSliderAutoHideTimer.value = null;
151
+ }
152
+ };
153
+
154
+ const handleMouseEnter = () => {
155
+ if (props.enableVolumeControl === false) return;
156
+
157
+ // Only handle mouse events on PC
158
+ if (isMobile) return;
159
+
160
+ // On PC, show volume slider and start auto-hide timer
161
+ isVolumeSliderVisible.value = true;
162
+ startVolumeSliderAutoHideTimer();
163
+ };
164
+
165
+ const handleMouseLeave = () => {
166
+ if (props.enableVolumeControl === false) return;
167
+ // Only handle mouse events on PC
168
+ if (isMobile) return;
169
+ // On PC, start auto-hide timer when mouse leaves icon area
170
+ // But don't start if currently dragging
171
+ if (!isDragging.value) {
172
+ startVolumeSliderAutoHideTimer();
173
+ }
174
+ };
175
+
176
+ const calculateVolumeFromPosition = (clientY: number, target: HTMLElement): number => {
177
+ const rect = target.getBoundingClientRect();
178
+ const clickY = clientY - rect.top;
179
+ const height = rect.height;
180
+ return Math.max(0, Math.min(1, 1 - clickY / height));
181
+ };
182
+
183
+ const addGlobalEventListeners = () => {
184
+ document.addEventListener('mousemove', handleSliderMove);
185
+ document.addEventListener('mouseup', handleSliderEnd);
186
+ document.addEventListener('touchmove', handleSliderMove);
187
+ document.addEventListener('touchend', handleSliderEnd);
188
+ };
189
+
190
+ const removeGlobalEventListeners = () => {
191
+ document.removeEventListener('mousemove', handleSliderMove);
192
+ document.removeEventListener('mouseup', handleSliderEnd);
193
+ document.removeEventListener('touchmove', handleSliderMove);
194
+ document.removeEventListener('touchend', handleSliderEnd);
195
+ };
196
+
197
+ const startDragging = () => {
198
+ isDragging.value = true;
199
+ // Stop auto-hide timer when dragging starts
200
+ if (props.enableVolumeControl) {
201
+ stopVolumeSliderAutoHideTimer();
202
+ }
203
+ addGlobalEventListeners();
204
+ };
205
+
206
+ const handleSliderMove = (event: MouseEvent | TouchEvent) => {
207
+ if (!isDragging.value) return;
208
+ event.preventDefault();
209
+ let clientY: number;
210
+ if (event instanceof MouseEvent) {
211
+ clientY = event.clientY;
212
+ } else {
213
+ clientY = event.touches[0].clientY;
214
+ }
215
+ const volumeValue = calculateVolumeFromPosition(clientY, volumeSliderElement.value as HTMLElement);
216
+ updateVolume(volumeValue);
217
+ };
218
+
219
+ const handleSliderEnd = () => {
220
+ isDragging.value = false;
221
+ // Restart auto-hide timer when dragging ends
222
+ if (props.enableVolumeControl && isVolumeSliderVisible.value) {
223
+ startVolumeSliderAutoHideTimer();
224
+ }
225
+ removeGlobalEventListeners();
226
+ };
227
+
228
+ const handleSliderMouseDown = (event: MouseEvent) => {
229
+ if (props.enableVolumeControl === false) return;
230
+ startDragging();
231
+ event.preventDefault();
232
+ };
233
+
234
+ const handleSliderTouchStart = (event: TouchEvent) => {
235
+ if (props.enableVolumeControl === false) return;
236
+ startDragging();
237
+ event.preventDefault();
238
+ };
239
+
240
+ const handleVolumeSliderAreaClick = () => {
241
+ if (props.enableVolumeControl === false) return;
242
+ if (isMobile) {
243
+ // On mobile, toggle volume slider visibility
244
+ isVolumeSliderVisible.value = !isVolumeSliderVisible.value;
245
+
246
+ // Start auto-hide timer when showing volume slider
247
+ if (isVolumeSliderVisible.value) {
248
+ startVolumeSliderAutoHideTimer();
249
+ } else {
250
+ stopVolumeSliderAutoHideTimer();
251
+ }
252
+ }
253
+ };
254
+
255
+ const handleVolumeSliderMouseEnter = () => {
256
+ if (props.enableVolumeControl === false) return;
257
+ // Only handle mouse events on PC
258
+ if (isMobile) return;
259
+ // On PC, stop auto-hide timer when mouse enters slider area
260
+ stopVolumeSliderAutoHideTimer();
261
+ };
262
+
263
+ const handleVolumeSliderMouseLeave = () => {
264
+ if (props.enableVolumeControl === false) return;
265
+ // Only handle mouse events on PC
266
+ if (isMobile) return;
267
+ // On PC, start auto-hide timer when mouse leaves slider area
268
+ // But don't start if currently dragging
269
+ if (!isDragging.value) {
270
+ startVolumeSliderAutoHideTimer();
271
+ }
272
+ };
273
+
274
+ onUnmounted(() => {
275
+ removeGlobalEventListeners();
276
+ if (volumeSliderAutoHideTimer.value) {
277
+ clearTimeout(volumeSliderAutoHideTimer.value);
278
+ }
279
+ });
280
+ </script>
281
+
282
+ <style scoped lang="scss">
283
+ .audio-control {
284
+ --volume-control-primary: rgb(255, 255, 255);
285
+ --volume-control-primary-hover: rgba(255, 255, 255, 0.1);
286
+ --volume-control-background: rgba(0, 0, 0, 0.8);
287
+ --volume-control-background-light: rgba(0, 0, 0, 0.5);
288
+ --volume-control-border: rgba(255, 255, 255, 0.1);
289
+ --volume-control-shadow: rgba(0, 0, 0, 0.2);
290
+
291
+ position: relative;
292
+ display: flex;
293
+ align-items: center;
294
+ }
295
+
296
+ .volume-btn {
297
+ width: 100%;
298
+ height: 100%;
299
+ flex-shrink: 0;
300
+ cursor: pointer;
301
+ transition: background-color 0.2s ease;
302
+ }
303
+
304
+ .volume-slider-container {
305
+ position: absolute;
306
+ bottom: 100%;
307
+ left: 50%;
308
+ transform: translateX(-50%);
309
+ margin-bottom: 12px;
310
+ z-index: 100;
311
+ }
312
+
313
+ .volume-slider-wrapper {
314
+ position: relative;
315
+ display: flex;
316
+ flex-direction: column;
317
+ align-items: center;
318
+ gap: 8px;
319
+ background: var(--volume-control-background);
320
+ padding: 12px 8px;
321
+ border-radius: 8px;
322
+ backdrop-filter: blur(10px);
323
+ border: 1px solid var(--volume-control-border);
324
+ cursor: pointer;
325
+ user-select: none;
326
+ -webkit-user-select: none;
327
+ -moz-user-select: none;
328
+ -ms-user-select: none;
329
+
330
+ @media (hover: none) and (pointer: coarse) {
331
+ cursor: grab;
332
+
333
+ &:active {
334
+ cursor: grabbing;
335
+ }
336
+ }
337
+ }
338
+
339
+ .volume-slider-wrapper-inner {
340
+ position: relative;
341
+ width: 20px;
342
+ height: 80px;
343
+ display: flex;
344
+ align-items: center;
345
+ justify-content: center;
346
+ margin-top: 12px;
347
+ }
348
+
349
+ .custom-volume-slider {
350
+ position: relative;
351
+ width: 4px;
352
+ height: 80px;
353
+ cursor: pointer;
354
+ z-index: 2;
355
+ margin: 0;
356
+ }
357
+
358
+ .slider-track {
359
+ position: absolute;
360
+ top: 0;
361
+ left: 0;
362
+ width: 100%;
363
+ height: 100%;
364
+ border-radius: 2px;
365
+ background: rgba(255, 255, 255, 0.2);
366
+ border: none;
367
+ }
368
+
369
+ .slider-progress {
370
+ position: absolute;
371
+ bottom: 0;
372
+ left: 0;
373
+ width: 100%;
374
+ background: #ffffff;
375
+ border-radius: 2px;
376
+ }
377
+
378
+ .slider-thumb {
379
+ $thumb-size: 12px;
380
+
381
+ position: absolute;
382
+ left: 50%;
383
+ transform: translateX(-50%);
384
+ width: $thumb-size;
385
+ height: $thumb-size;
386
+ background: #ffffff;
387
+ border-radius: 50%;
388
+ border: 2px solid rgba(255, 255, 255, 0.8);
389
+ box-shadow: 0 2px 4px rgba(0, 0, 0, 0.3);
390
+ transition: transform 0.1s ease;
391
+ z-index: 3;
392
+ cursor: grab;
393
+
394
+ &.no-transition {
395
+ transition: none;
396
+ }
397
+
398
+ &:active {
399
+ cursor: grabbing;
400
+ transform: translateX(-50%) scale(1.1);
401
+ }
402
+
403
+ &:hover {
404
+ transform: translateX(-50%) scale(1.1);
405
+ }
406
+ }
407
+
408
+ .volume-value {
409
+ color: var(--volume-control-primary);
410
+ font-size: 12px;
411
+ font-weight: 500;
412
+ text-align: center;
413
+ min-width: 32px;
414
+ padding: 2px 6px;
415
+ border-radius: 4px;
416
+ pointer-events: none;
417
+ }
418
+
419
+ @media (hover: none) and (pointer: coarse) {
420
+ .volume-slider-wrapper {
421
+ padding: 16px 12px;
422
+
423
+ &:active {
424
+ background: var(--volume-control-background-light);
425
+ transform: scale(0.98);
426
+ transition: all 0.1s ease;
427
+ }
428
+ }
429
+
430
+ .volume-slider-wrapper-inner {
431
+ height: 100px;
432
+ }
433
+ }
434
+ </style>
@@ -0,0 +1,52 @@
1
+ // Fullscreen mode base styles
2
+ .fullscreen-mode {
3
+ width: 100vw !important;
4
+ height: 100vh !important;
5
+ z-index: 9999 !important;
6
+ background-color: #000 !important;
7
+ }
8
+
9
+ // H5 portrait stream fullscreen mode (preserve original width/height, no forced modification)
10
+ .fullscreen-mode-portrait {
11
+ z-index: 9999 !important;
12
+ background-color: #000 !important;
13
+ // Note: Do not modify width and height, preserve original styles
14
+ }
15
+
16
+ // Landscape mode styles - Only apply CSS rotation when device is in portrait
17
+ .landscape-mode {
18
+ transform: rotate(90deg) !important;
19
+ transform-origin: center center !important;
20
+ width: 100vh !important;
21
+ height: 100vw !important;
22
+ overflow: hidden !important;
23
+ // Add smooth transition effect
24
+ transition: transform 0.3s ease-in-out !important;
25
+ }
26
+
27
+ // When device is in landscape, remove CSS rotation to avoid double rotation
28
+ @media screen and (orientation: landscape) {
29
+ .landscape-mode {
30
+ transform: none !important;
31
+ width: 100vw !important;
32
+ height: 100vh !important;
33
+ }
34
+ }
35
+
36
+ // Mobile device landscape optimization
37
+ @media screen and (orientation: landscape) and (max-width: 768px) {
38
+ .live-core-view.landscape-mode {
39
+ // Ensure correct display in landscape
40
+ background-color: #000;
41
+ transform: none !important;
42
+ }
43
+ }
44
+
45
+ // Force landscape display on mobile portrait
46
+ @media screen and (orientation: portrait) and (max-width: 768px) {
47
+ .live-core-view.landscape-mode {
48
+ // Force landscape display in portrait
49
+ transform: rotate(90deg) !important;
50
+ transform-origin: center center !important;
51
+ }
52
+ }