@trtc/calls-uikit-react 4.4.2 → 4.4.3-beta.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.
@@ -136,6 +136,5 @@ export declare const en: {
136
136
  'error.10008': string;
137
137
  'error.10012': string;
138
138
  'error.10013': string;
139
- 'error.10014': string;
140
139
  error: string;
141
140
  };
@@ -135,6 +135,5 @@ export declare const ja_JP: {
135
135
  'error.10008': string;
136
136
  'error.10012': string;
137
137
  'error.10013': string;
138
- 'error.10014': string;
139
138
  error: string;
140
139
  };
@@ -131,6 +131,5 @@ export declare const zh: {
131
131
  'error.10008': string;
132
132
  'error.10012': string;
133
133
  'error.10013': string;
134
- 'error.10014': string;
135
134
  error: string;
136
135
  };
@@ -0,0 +1,5 @@
1
+ interface IStatusValidateParams {
2
+ engineInstance?: boolean;
3
+ }
4
+ export declare function statusValidate(config: IStatusValidateParams): (target: any, propertyName: string, descriptor: PropertyDescriptor) => PropertyDescriptor;
5
+ export {};
@@ -1,250 +0,0 @@
1
- import React, { useState, useEffect, useCallback, useMemo } from 'react';
2
- import { createPortal } from 'react-dom';
3
- import ReactDOM from 'react-dom/client';
4
- import type { ReactNode } from 'react';
5
- import { uikitModalState } from './UIKitModalState';
6
- import { IS_PC } from '../../../../TUICallService/utils/env';
7
- import { t } from '../../../../TUICallService';
8
- import styles from './index.module.scss';
9
-
10
- // Types
11
- export interface UIKitModalConfig {
12
- id: number;
13
- title: string;
14
- content: string | ReactNode;
15
- type: 'info' | 'warning' | 'error' | 'success';
16
- onConfirm?: () => void;
17
- onCancel?: () => void;
18
- }
19
-
20
- export type UIKitModalOptions = UIKitModalConfig;
21
-
22
- // Constants
23
- let root: ReactDOM.Root | null = null;
24
- let container: HTMLDivElement | null = null;
25
- let resolvePromise: ((value: { action: string }) => void) | null = null;
26
-
27
- const URL_REGEX = /^(https?:\/\/)?([\da-z.-]+)\.([a-z.]{2,6})([/\w .-]*)*\/?$/i;
28
- const FULL_URL_REGEX = /(https?:\/\/[^\s]+)/g;
29
-
30
- function escapeHtml(text: string): string {
31
- const div = document.createElement('div');
32
- div.textContent = text;
33
- return div.innerHTML;
34
- }
35
-
36
- function processAnchorTags(content: string): string {
37
- const parser = new DOMParser();
38
- const doc = parser.parseFromString(content, 'text/html');
39
- const anchors = doc.querySelectorAll('a');
40
- anchors.forEach((anchor) => {
41
- const href = anchor.getAttribute('href');
42
- if (href) {
43
- anchor.setAttribute('target', '_blank');
44
- anchor.setAttribute('rel', 'noopener noreferrer');
45
- anchor.classList.add(styles['uikit-modal-link']);
46
- const originalText = anchor.textContent || '';
47
- anchor.innerHTML = `<span style="padding: 0 0.2em; display: inline-block; color: var(--text-color-link)">${originalText}</span>`;
48
- }
49
- });
50
- return doc.body.innerHTML;
51
- }
52
-
53
- const TypeIcons: Record<string, () => JSX.Element> = {
54
- success: () => <span style={{ color: 'green', marginRight: '6px' }}>✓</span>,
55
- info: () => <span style={{ color: '#1890ff', marginRight: '6px' }}>ℹ</span>,
56
- error: () => <span style={{ color: 'red', marginRight: '6px' }}>✕</span>,
57
- warning: () => <span style={{ color: '#faad14', marginRight: '6px' }}>⚠</span>,
58
- };
59
-
60
- const isLocalEnvironment = (): boolean => {
61
- const { hostname: host, href } = window.location;
62
- if (host === 'localhost' || host === '127.0.0.1' || host.startsWith('192.168.')) {
63
- return true;
64
- }
65
- if (href.startsWith('https://web.sdk.qcloud.com/trtc/livekit')) {
66
- return true;
67
- }
68
- return false;
69
- };
70
-
71
- const cleanup = () => {
72
- if (root) {
73
- root.unmount();
74
- root = null;
75
- }
76
- if (container && container.parentNode) {
77
- container.parentNode.removeChild(container);
78
- container = null;
79
- }
80
- resolvePromise = null;
81
- };
82
-
83
- interface UIKitModalComponentProps extends UIKitModalOptions {
84
- visible: boolean;
85
- }
86
-
87
- export function UIKitModalComponent(props: UIKitModalComponentProps) {
88
- const {
89
- type = 'info',
90
- title = '',
91
- content = '',
92
- visible = false,
93
- onConfirm,
94
- onCancel,
95
- } = props;
96
-
97
- const cancelText = t('reject');
98
- const confirmText = t('accept');
99
-
100
- const modalContainerClass = IS_PC
101
- ? `${styles['uikit-modal-default']} ${styles['uikit-modal-container']}`
102
- : `${styles['uikit-modal-default']} ${styles['uikit-modal-container']} ${styles['uikit-modal-container-mobile']}`;
103
-
104
- const processedContent = useMemo(() => {
105
- if (!content || typeof content !== 'string') {
106
- return content;
107
- }
108
-
109
- if (URL_REGEX.test(content.trim())) {
110
- const url = content.trim();
111
- const href = url.startsWith('http') ? url : `https://${url}`;
112
- return `<a href="${escapeHtml(href)}" target="_blank" rel="noopener noreferrer" class="${styles['uikit-modal-link']}">${escapeHtml(url)}</a>`;
113
- }
114
-
115
- if (content.includes('<a ') || content.includes('<a>')) {
116
- return processAnchorTags(content);
117
- }
118
-
119
- if (FULL_URL_REGEX.test(content)) {
120
- return escapeHtml(content).replace(FULL_URL_REGEX, url => `<a href="${url}" target="_blank" rel="noopener noreferrer" class="${styles['uikit-modal-link']}">${url}</a>`);
121
- }
122
-
123
- return escapeHtml(content);
124
- }, [content]);
125
-
126
- const TypeIcon = TypeIcons[type] || TypeIcons.info;
127
-
128
- if (!visible) {
129
- return null;
130
- }
131
-
132
- const modalContent = (
133
- <div
134
- className={styles['uikit-modal-mask']}
135
- onClick={onConfirm}
136
- >
137
- <div
138
- className={modalContainerClass}
139
- onClick={e => e.stopPropagation()}
140
- >
141
- <div className={styles['uikit-modal-header']}>
142
- <TypeIcon />
143
- <span className={styles['uikit-modal-title']}>{title}</span>
144
- </div>
145
- <div
146
- className={styles['uikit-modal-body']}
147
- dangerouslySetInnerHTML={typeof processedContent === 'string' ? { __html: processedContent } : undefined}
148
- >
149
- {typeof processedContent !== 'string' ? processedContent : null}
150
- </div>
151
- <div className={styles['uikit-modal-footer']}>
152
- <button
153
- className={`${styles['uikit-modal-btn']} ${styles['uikit-modal-btn-cancel']}`}
154
- onClick={onCancel}
155
- >
156
- {cancelText || 'Cancel'}
157
- </button>
158
- <button
159
- className={`${styles['uikit-modal-btn']} ${styles['uikit-modal-btn-confirm']}`}
160
- onClick={onConfirm}
161
- >
162
- {confirmText || 'Confirm'}
163
- </button>
164
- </div>
165
- </div>
166
- </div>
167
- );
168
-
169
- return createPortal(modalContent, document.body);
170
- }
171
-
172
- interface UIKitModalWrapperProps {
173
- options: UIKitModalOptions;
174
- }
175
-
176
- function UIKitModalWrapper(props: UIKitModalWrapperProps) {
177
- const { options } = props;
178
- const [visible, setVisible] = useState(true);
179
-
180
- const handleAction = useCallback((action: 'confirm' | 'cancel') => {
181
- const { closeModal } = uikitModalState.getState();
182
- setVisible(false);
183
- closeModal(action);
184
- if (resolvePromise) {
185
- resolvePromise({ action });
186
- }
187
- setTimeout(cleanup, 100);
188
- }, []);
189
-
190
- const handleConfirm = useCallback(() => {
191
- options.onConfirm?.();
192
- handleAction('confirm');
193
- }, [options, handleAction]);
194
-
195
- const handleCancel = useCallback(() => {
196
- options.onCancel?.();
197
- handleAction('cancel');
198
- }, [options, handleAction]);
199
-
200
- useEffect(() => {
201
- const handleKeyDown = (e: KeyboardEvent) => {
202
- if (e.key === 'Escape') {
203
- handleCancel();
204
- }
205
- };
206
- document.addEventListener('keydown', handleKeyDown);
207
- return () => document.removeEventListener('keydown', handleKeyDown);
208
- }, [handleCancel]);
209
-
210
- return (
211
- <UIKitModalComponent
212
- {...options}
213
- visible={visible}
214
- onConfirm={handleConfirm}
215
- onCancel={handleCancel}
216
- />
217
- );
218
- }
219
-
220
- const createUIKitModal = (options: UIKitModalOptions): Promise<{ action: string }> => new Promise((resolve) => {
221
- cleanup();
222
-
223
- const { openModal } = uikitModalState.getState();
224
-
225
- openModal({
226
- id: options.id,
227
- title: options.title,
228
- content: options.content,
229
- type: options.type,
230
- ...(options.onConfirm && { onConfirm: options.onConfirm }),
231
- ...(options.onCancel && { onCancel: options.onCancel }),
232
- });
233
-
234
- if (!isLocalEnvironment()) {
235
- resolve({ action: 'confirm' });
236
- return;
237
- }
238
-
239
- resolvePromise = resolve;
240
-
241
- container = document.createElement('div');
242
- container.id = 'uikit-modal-root';
243
- document.body.appendChild(container);
244
- root = ReactDOM.createRoot(container);
245
- root.render(React.createElement(UIKitModalWrapper, { options }));
246
- });
247
-
248
- export const UIKitModal = {
249
- openModal: (config: UIKitModalOptions) => createUIKitModal(config),
250
- };
@@ -1,177 +0,0 @@
1
- import type { ReactNode } from 'react';
2
- import { TUICallKitAPI } from '../../../../TUICallService/index';
3
-
4
- // Types
5
- export interface UIKitModalConfig {
6
- id: number;
7
- title: string;
8
- content: string | ReactNode;
9
- type: 'info' | 'warning' | 'error' | 'success';
10
- onConfirm?: () => void;
11
- onCancel?: () => void;
12
- }
13
-
14
- export type UIKitModalOptions = UIKitModalConfig;
15
-
16
- interface AnalyticsData {
17
- eventType: number;
18
- modalId: number;
19
- title: string;
20
- type: string;
21
- content: string | ReactNode;
22
- timestamp: number;
23
- stayDuration?: number;
24
- closeReasonCode?: number;
25
- sessionId?: string;
26
- platformCode?: number;
27
- userAgent?: string;
28
- }
29
-
30
- interface UIKitModalState {
31
- modalData: UIKitModalConfig | null;
32
- activeModalId: number | null;
33
- modalOpenTime: number | null;
34
- }
35
-
36
- interface UIKitModalActions {
37
- openModal: (config: UIKitModalConfig) => void;
38
- closeModal: (action?: 'confirm' | 'cancel' | 'mask' | 'timeout') => void;
39
- getState: () => UIKitModalState & UIKitModalActions;
40
- }
41
-
42
- function getPlatformInfo() {
43
- const ua = navigator.userAgent;
44
- const isMobile = /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(ua);
45
- return {
46
- userAgent: ua,
47
- platformCode: isMobile ? 2 : 1,
48
- };
49
- }
50
-
51
- function getSessionId(): string {
52
- let sessionId = sessionStorage.getItem('uikit_session_id');
53
- if (!sessionId) {
54
- sessionId = `session_${Date.now()}_${Math.random().toString(36).substring(2, 11)}`;
55
- sessionStorage.setItem('uikit_session_id', sessionId);
56
- }
57
- return sessionId;
58
- }
59
-
60
- function reportAnalytics(data: AnalyticsData) {
61
- try {
62
- // IM report
63
- const tim = TUICallKitAPI.getTim();
64
- if (tim && typeof tim.callExperimentalAPI === 'function') {
65
- const reportData = {
66
- id: data.modalId,
67
- title: data.title,
68
- type: data.type,
69
- content: data.content,
70
- };
71
- tim.callExperimentalAPI('reportModalView', JSON.stringify(reportData));
72
- }
73
- } catch (_error) {
74
- console.info('[UIKitModal]', data);
75
- }
76
- }
77
-
78
- const createUIKitModalStore = () => {
79
- let state: UIKitModalState = {
80
- modalData: null,
81
- activeModalId: null,
82
- modalOpenTime: null,
83
- };
84
-
85
- const listeners: Set<() => void> = new Set();
86
-
87
- const notify = () => {
88
- listeners.forEach(listener => listener());
89
- };
90
-
91
- const openModal = (config: UIKitModalConfig) => {
92
- const now = Date.now();
93
- const { userAgent, platformCode } = getPlatformInfo();
94
-
95
- state = {
96
- modalData: config,
97
- activeModalId: config.id,
98
- modalOpenTime: now,
99
- };
100
-
101
- reportAnalytics({
102
- eventType: 1,
103
- modalId: config.id,
104
- title: config.title,
105
- type: config.type,
106
- content: config.content,
107
- timestamp: now,
108
- sessionId: getSessionId(),
109
- platformCode,
110
- userAgent,
111
- });
112
-
113
- notify();
114
- };
115
-
116
- const closeModal = (action: 'confirm' | 'cancel' | 'mask' | 'timeout' = 'confirm') => {
117
- const { activeModalId, modalOpenTime, modalData } = state;
118
-
119
- if (activeModalId === null || !modalOpenTime || !modalData) {
120
- return;
121
- }
122
-
123
- const now = Date.now();
124
- const stayDuration = now - modalOpenTime;
125
- const { userAgent, platformCode } = getPlatformInfo();
126
-
127
- const closeReasonCodeMap: Record<string, number> = {
128
- confirm: 1,
129
- cancel: 2,
130
- timeout: 3,
131
- mask: 2,
132
- };
133
-
134
- reportAnalytics({
135
- eventType: 2,
136
- modalId: activeModalId,
137
- title: modalData.title,
138
- type: modalData.type,
139
- content: modalData.content,
140
- timestamp: now,
141
- stayDuration,
142
- closeReasonCode: closeReasonCodeMap[action],
143
- sessionId: getSessionId(),
144
- platformCode,
145
- userAgent,
146
- });
147
-
148
- state = {
149
- modalData: null,
150
- activeModalId: null,
151
- modalOpenTime: null,
152
- };
153
-
154
- notify();
155
- };
156
-
157
- const getState = (): UIKitModalState & UIKitModalActions => ({
158
- ...state,
159
- openModal,
160
- closeModal,
161
- getState,
162
- });
163
-
164
- return {
165
- getState,
166
- openModal,
167
- closeModal,
168
- subscribe: (listener: () => void) => {
169
- listeners.add(listener);
170
- return () => listeners.delete(listener);
171
- },
172
- };
173
- };
174
-
175
- export const uikitModalState = createUIKitModalStore();
176
-
177
- export default uikitModalState;
@@ -1,176 +0,0 @@
1
- .uikit-modal-mask {
2
- position: fixed;
3
- top: 0;
4
- left: 0;
5
- width: 100vw;
6
- height: 100vh;
7
- background: rgba(0, 0, 0, 0.6);
8
- z-index: 9999;
9
- display: flex;
10
- align-items: center;
11
- justify-content: center;
12
- }
13
-
14
- .uikit-modal-default {
15
- width: 480px;
16
- max-width: calc(100% - 40px);
17
- box-shadow: 0 2px 12px rgba(0, 0, 0, 0.15);
18
- }
19
-
20
- .uikit-modal-container {
21
- box-sizing: border-box;
22
- background: #fff;
23
- position: relative;
24
- display: flex;
25
- flex-direction: column;
26
- overflow: hidden;
27
- padding: 24px;
28
- border-radius: 20px;
29
- }
30
-
31
- .uikit-modal-header {
32
- display: flex;
33
- justify-content: space-between;
34
- align-items: center;
35
- padding-bottom: 20px;
36
- }
37
-
38
- .uikit-modal-type-icon {
39
- margin-right: 6px;
40
- }
41
-
42
- .uikit-modal-close-icon {
43
- cursor: pointer;
44
- color: #333;
45
- }
46
-
47
- .uikit-modal-title {
48
- font-size: 16px;
49
- line-height: 24px;
50
- font-weight: 600;
51
- color: #333;
52
- flex: 1;
53
- }
54
-
55
- .uikit-modal-body {
56
- flex: 1;
57
- display: block;
58
- font-size: 14px;
59
- font-weight: 400;
60
- line-height: 22px;
61
- color: #333;
62
- word-break: break-word;
63
- }
64
-
65
- .uikit-modal-link {
66
- color: #006eff;
67
- text-decoration: none;
68
- transition: all 0.2s ease;
69
- cursor: pointer;
70
- border-bottom: 1px solid transparent;
71
- margin: 0 0.2em;
72
- }
73
-
74
- .uikit-modal-footer {
75
- padding-top: 20px;
76
- box-sizing: border-box;
77
- display: flex;
78
- justify-content: flex-end;
79
- gap: 12px;
80
- }
81
-
82
- .uikit-modal-btn {
83
- min-width: 88px;
84
- height: 32px;
85
- padding: 0 16px;
86
- border-radius: 20px;
87
- font-size: 14px;
88
- font-weight: 500;
89
- cursor: pointer;
90
- transition: all 0.2s ease;
91
- border: none;
92
- outline: none;
93
- white-space: nowrap;
94
-
95
- &:active {
96
- transform: scale(0.98);
97
- }
98
- }
99
-
100
- .uikit-modal-btn-cancel {
101
- background: #f0f2f9;
102
- color: #333;
103
-
104
- &:hover {
105
- background: #e5e7ed;
106
- }
107
- }
108
-
109
- .uikit-modal-btn-confirm {
110
- background: #1c66e5;
111
- color: #fff;
112
-
113
- &:hover {
114
- background: #1557cc;
115
- }
116
- }
117
-
118
- .uikit-modal-header:empty,
119
- .uikit-modal-body:empty,
120
- .uikit-modal-footer:empty {
121
- padding: 0;
122
- }
123
-
124
- .uikit-modal-container-mobile {
125
- border-radius: 12px;
126
- max-width: calc(100% - 32px);
127
- padding: 0;
128
-
129
- .uikit-modal-header {
130
- padding: 20px 20px 16px;
131
- justify-content: flex-start;
132
- }
133
-
134
- .uikit-modal-body {
135
- padding: 0 20px 20px;
136
- justify-content: flex-start;
137
- }
138
-
139
- .uikit-modal-footer {
140
- padding: 0;
141
- border-top: 0.5px solid #e5e5e5;
142
- gap: 0;
143
-
144
- .uikit-modal-btn {
145
- flex: 1;
146
- border-radius: 0;
147
- height: 56px;
148
- min-width: auto;
149
- background: #fff;
150
- font-size: 17px;
151
-
152
- &:active {
153
- transform: none;
154
- background: #f5f5f5;
155
- }
156
-
157
- &:hover {
158
- background: #fff;
159
- }
160
- }
161
-
162
- .uikit-modal-btn-cancel {
163
- color: #666;
164
-
165
- &:first-child:last-child {
166
- border-radius: 0 0 12px 12px;
167
- }
168
- }
169
-
170
- .uikit-modal-btn-confirm {
171
- color: #1c66e5;
172
- border-left: 0.5px solid #e5e5e5;
173
- font-weight: 600;
174
- }
175
- }
176
- }
@@ -1,3 +0,0 @@
1
- export { UIKitModal, UIKitModalComponent } from './UIKitModal';
2
- export type { UIKitModalConfig, UIKitModalOptions } from './UIKitModal';
3
- export { uikitModalState } from './UIKitModalState';
@@ -1,21 +0,0 @@
1
- import React from 'react';
2
- import type { ReactNode } from 'react';
3
- export interface UIKitModalConfig {
4
- id: number;
5
- title: string;
6
- content: string | ReactNode;
7
- type: 'info' | 'warning' | 'error' | 'success';
8
- onConfirm?: () => void;
9
- onCancel?: () => void;
10
- }
11
- export type UIKitModalOptions = UIKitModalConfig;
12
- interface UIKitModalComponentProps extends UIKitModalOptions {
13
- visible: boolean;
14
- }
15
- export declare function UIKitModalComponent(props: UIKitModalComponentProps): React.ReactPortal;
16
- export declare const UIKitModal: {
17
- openModal: (config: UIKitModalOptions) => Promise<{
18
- action: string;
19
- }>;
20
- };
21
- export {};
@@ -1,27 +0,0 @@
1
- import type { ReactNode } from 'react';
2
- export interface UIKitModalConfig {
3
- id: number;
4
- title: string;
5
- content: string | ReactNode;
6
- type: 'info' | 'warning' | 'error' | 'success';
7
- onConfirm?: () => void;
8
- onCancel?: () => void;
9
- }
10
- export type UIKitModalOptions = UIKitModalConfig;
11
- interface UIKitModalState {
12
- modalData: UIKitModalConfig | null;
13
- activeModalId: number | null;
14
- modalOpenTime: number | null;
15
- }
16
- interface UIKitModalActions {
17
- openModal: (config: UIKitModalConfig) => void;
18
- closeModal: (action?: 'confirm' | 'cancel' | 'mask' | 'timeout') => void;
19
- getState: () => UIKitModalState & UIKitModalActions;
20
- }
21
- export declare const uikitModalState: {
22
- getState: () => UIKitModalState & UIKitModalActions;
23
- openModal: (config: UIKitModalConfig) => void;
24
- closeModal: (action?: "confirm" | "cancel" | "mask" | "timeout") => void;
25
- subscribe: (listener: () => void) => () => boolean;
26
- };
27
- export default uikitModalState;
@@ -1,3 +0,0 @@
1
- export { UIKitModal, UIKitModalComponent } from './UIKitModal';
2
- export type { UIKitModalConfig, UIKitModalOptions } from './UIKitModal';
3
- export { uikitModalState } from './UIKitModalState';