funda-ui 4.7.585 → 4.7.601
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/Chatbox/index.js +1564 -506
- package/EventCalendar/index.js +2 -1
- package/EventCalendarTimeline/index.js +2 -1
- package/LiveSearch/index.js +341 -21
- package/MultipleCheckboxes/index.js +341 -21
- package/MultipleSelect/index.js +341 -21
- package/NativeSelect/index.js +341 -21
- package/Radio/index.js +341 -21
- package/Select/index.js +341 -21
- package/Utils/anim.js +338 -22
- package/Utils/initDefaultOptions.js +338 -22
- package/Utils/validate.d.ts +16 -6
- package/Utils/validate.js +338 -21
- package/lib/cjs/Chatbox/index.js +1564 -506
- package/lib/cjs/EventCalendar/index.js +2 -1
- package/lib/cjs/EventCalendarTimeline/index.js +2 -1
- package/lib/cjs/LiveSearch/index.js +341 -21
- package/lib/cjs/MultipleCheckboxes/index.js +341 -21
- package/lib/cjs/MultipleSelect/index.js +341 -21
- package/lib/cjs/NativeSelect/index.js +341 -21
- package/lib/cjs/Radio/index.js +341 -21
- package/lib/cjs/Select/index.js +341 -21
- package/lib/cjs/Utils/anim.js +338 -22
- package/lib/cjs/Utils/initDefaultOptions.js +338 -22
- package/lib/cjs/Utils/validate.d.ts +16 -6
- package/lib/cjs/Utils/validate.js +338 -21
- package/lib/esm/Chatbox/index.tsx +15 -11
- package/lib/esm/Chatbox/utils/func.ts +10 -10
- package/lib/esm/EventCalendar/index.tsx +2 -1
- package/lib/esm/EventCalendarTimeline/index.tsx +2 -1
- package/lib/esm/Utils/libs/validate.ts +367 -26
- package/package.json +1 -1
- package/lib/esm/Chatbox/useStreamController.tsx +0 -277
|
@@ -1,277 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Stream Controller
|
|
3
|
-
*
|
|
4
|
-
* @usage:
|
|
5
|
-
|
|
6
|
-
// Use in component
|
|
7
|
-
const streamController = useStreamController({
|
|
8
|
-
onChunk: async (chunk: string, index: number) => {
|
|
9
|
-
// start (Execute it only once)
|
|
10
|
-
if (index === 0) {
|
|
11
|
-
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
// Streaming data is JSON split by rows
|
|
15
|
-
const lines = chunk.split("\n").filter(line => line.trim() !== "");
|
|
16
|
-
|
|
17
|
-
// Process each data chunk
|
|
18
|
-
console.log('Received chunk:', chunk);
|
|
19
|
-
},
|
|
20
|
-
onComplete: async (lastContent: string) => {
|
|
21
|
-
// Process when stream is completed
|
|
22
|
-
console.log('Stream completed');
|
|
23
|
-
|
|
24
|
-
// Display AI reply
|
|
25
|
-
console.log('AI reply:', lastContent);
|
|
26
|
-
|
|
27
|
-
},
|
|
28
|
-
onError: (error) => {
|
|
29
|
-
// Error handling
|
|
30
|
-
console.error('Stream error:', error);
|
|
31
|
-
},
|
|
32
|
-
onAbort: () => {
|
|
33
|
-
// Abort processing
|
|
34
|
-
console.log('Stream aborted');
|
|
35
|
-
}
|
|
36
|
-
});
|
|
37
|
-
|
|
38
|
-
// Start stream
|
|
39
|
-
const response = await fetch(url);
|
|
40
|
-
await streamController.start(response);
|
|
41
|
-
|
|
42
|
-
// Pause stream
|
|
43
|
-
streamController.pause();
|
|
44
|
-
|
|
45
|
-
// Resume stream
|
|
46
|
-
streamController.resume();
|
|
47
|
-
|
|
48
|
-
// Abort stream
|
|
49
|
-
streamController.abort();
|
|
50
|
-
|
|
51
|
-
// Check status
|
|
52
|
-
const isActive = streamController.isActive();
|
|
53
|
-
const isPaused = streamController.isPaused();
|
|
54
|
-
|
|
55
|
-
*/
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
import { useRef, useCallback, useEffect } from 'react';
|
|
59
|
-
|
|
60
|
-
export interface StreamControllerOptions {
|
|
61
|
-
onChunk?: (chunk: string, index: number) => void;
|
|
62
|
-
onComplete?: (lastContent: string) => void;
|
|
63
|
-
onError?: (error: any) => void;
|
|
64
|
-
onAbort?: () => void;
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
export interface StreamController {
|
|
68
|
-
start: (response: Response) => Promise<void>;
|
|
69
|
-
pause: () => void;
|
|
70
|
-
resume: () => void;
|
|
71
|
-
abort: () => void;
|
|
72
|
-
isActive: () => boolean;
|
|
73
|
-
isPaused: () => boolean;
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
export const useStreamController = (options: StreamControllerOptions = {}): StreamController => {
|
|
77
|
-
const streamController = useRef<ReadableStreamDefaultController | null>(null);
|
|
78
|
-
const reader = useRef<ReadableStreamDefaultReader | null>(null);
|
|
79
|
-
const activeStream = useRef<ReadableStream | null>(null);
|
|
80
|
-
const responseReader = useRef<ReadableStreamDefaultReader | null>(null);
|
|
81
|
-
const paused = useRef<boolean>(false);
|
|
82
|
-
const active = useRef<boolean>(false);
|
|
83
|
-
const abortController = useRef<AbortController>(new AbortController());
|
|
84
|
-
const textDecoder = useRef<TextDecoder>(new TextDecoder("utf-8")); // Get the decoding of UTF8
|
|
85
|
-
|
|
86
|
-
// To avoid the "Uncaught (in promise) TypeError: Failed to execute 'cancel' on 'ReadableStream': Cannot cancel a locked stream" error,
|
|
87
|
-
// (1) you need to safely release the reader.
|
|
88
|
-
// (2) cleanup() also requires asynchronous state
|
|
89
|
-
const releaseReader = useCallback(async (readerRef: React.MutableRefObject<ReadableStreamDefaultReader | null>) => {
|
|
90
|
-
if (readerRef.current) {
|
|
91
|
-
try {
|
|
92
|
-
await readerRef.current.cancel();
|
|
93
|
-
} catch (e) {
|
|
94
|
-
console.warn('Error cancelling reader:', e);
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
try {
|
|
98
|
-
readerRef.current.releaseLock();
|
|
99
|
-
} catch (e) {
|
|
100
|
-
console.warn('Error releasing reader lock:', e);
|
|
101
|
-
}
|
|
102
|
-
readerRef.current = null;
|
|
103
|
-
}
|
|
104
|
-
}, []);
|
|
105
|
-
|
|
106
|
-
const cleanup = useCallback(async () => {
|
|
107
|
-
// First release all readers
|
|
108
|
-
await releaseReader(reader);
|
|
109
|
-
await releaseReader(responseReader);
|
|
110
|
-
|
|
111
|
-
// Then try to cancel the stream
|
|
112
|
-
if (activeStream.current) {
|
|
113
|
-
try {
|
|
114
|
-
await activeStream.current.cancel();
|
|
115
|
-
} catch (e) {
|
|
116
|
-
console.warn('Error cancelling stream:', e);
|
|
117
|
-
}
|
|
118
|
-
activeStream.current = null;
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
streamController.current = null;
|
|
122
|
-
active.current = false;
|
|
123
|
-
paused.current = false;
|
|
124
|
-
}, [releaseReader]);
|
|
125
|
-
|
|
126
|
-
// Process chunks of data
|
|
127
|
-
const processChunk = useCallback(async (chunk: string, index: number) => {
|
|
128
|
-
try {
|
|
129
|
-
options.onChunk?.(chunk, index);
|
|
130
|
-
} catch (error) {
|
|
131
|
-
options.onError?.(error);
|
|
132
|
-
}
|
|
133
|
-
}, [options]);
|
|
134
|
-
|
|
135
|
-
// Start processing the stream
|
|
136
|
-
const startProcessing = useCallback(async () => {
|
|
137
|
-
if (!reader.current || !active.current) return;
|
|
138
|
-
|
|
139
|
-
//
|
|
140
|
-
let counter = 0;
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
// Store the final content and bind it to loading
|
|
144
|
-
let lastContent: string = '';
|
|
145
|
-
|
|
146
|
-
while (active.current) {
|
|
147
|
-
try {
|
|
148
|
-
|
|
149
|
-
if (paused.current) {
|
|
150
|
-
await new Promise(resolve => setTimeout(resolve, 100));
|
|
151
|
-
continue;
|
|
152
|
-
}
|
|
153
|
-
|
|
154
|
-
const { done, value } = await reader.current.read();
|
|
155
|
-
|
|
156
|
-
if (done) {
|
|
157
|
-
options.onComplete?.(lastContent);
|
|
158
|
-
await cleanup();
|
|
159
|
-
break;
|
|
160
|
-
}
|
|
161
|
-
|
|
162
|
-
// Decode the content
|
|
163
|
-
const chunkStr = textDecoder.current.decode(value as Uint8Array, { stream: true });
|
|
164
|
-
lastContent += chunkStr;
|
|
165
|
-
|
|
166
|
-
await processChunk(chunkStr, counter);
|
|
167
|
-
counter++;
|
|
168
|
-
|
|
169
|
-
} catch (error: any) {
|
|
170
|
-
if (error.name === 'AbortError') {
|
|
171
|
-
options.onAbort?.();
|
|
172
|
-
} else {
|
|
173
|
-
options.onError?.(error);
|
|
174
|
-
}
|
|
175
|
-
await cleanup();
|
|
176
|
-
break;
|
|
177
|
-
}
|
|
178
|
-
|
|
179
|
-
}
|
|
180
|
-
}, [options, cleanup, processChunk]);
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
// Start streaming
|
|
184
|
-
const start = useCallback(async (response: Response) => {
|
|
185
|
-
await cleanup();
|
|
186
|
-
|
|
187
|
-
// Get Reader
|
|
188
|
-
reader.current = response.body!.getReader();
|
|
189
|
-
|
|
190
|
-
try {
|
|
191
|
-
|
|
192
|
-
const stream = new ReadableStream({
|
|
193
|
-
start(controller) {
|
|
194
|
-
streamController.current = controller;
|
|
195
|
-
},
|
|
196
|
-
async pull(controller) {
|
|
197
|
-
try {
|
|
198
|
-
const { done, value } = await reader.current!.read();
|
|
199
|
-
|
|
200
|
-
if (done) {
|
|
201
|
-
controller.close();
|
|
202
|
-
return;
|
|
203
|
-
}
|
|
204
|
-
|
|
205
|
-
// Decode the content
|
|
206
|
-
const chunkStr = textDecoder.current.decode(value as Uint8Array, { stream: true });
|
|
207
|
-
|
|
208
|
-
controller.enqueue(chunkStr);
|
|
209
|
-
} catch (error) {
|
|
210
|
-
controller.error(error);
|
|
211
|
-
}
|
|
212
|
-
},
|
|
213
|
-
cancel() {
|
|
214
|
-
response.body?.cancel();
|
|
215
|
-
}
|
|
216
|
-
});
|
|
217
|
-
|
|
218
|
-
activeStream.current = stream;
|
|
219
|
-
active.current = true;
|
|
220
|
-
paused.current = false;
|
|
221
|
-
|
|
222
|
-
// Start processing immediately
|
|
223
|
-
await startProcessing();
|
|
224
|
-
} catch (error) {
|
|
225
|
-
options.onError?.(error);
|
|
226
|
-
cleanup();
|
|
227
|
-
}
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
}, [options, cleanup, startProcessing]);
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
// Pause streaming
|
|
235
|
-
const pause = useCallback(() => {
|
|
236
|
-
paused.current = true;
|
|
237
|
-
}, []);
|
|
238
|
-
|
|
239
|
-
// Resume streaming
|
|
240
|
-
const resume = useCallback(() => {
|
|
241
|
-
paused.current = false;
|
|
242
|
-
}, []);
|
|
243
|
-
|
|
244
|
-
// Abort streaming
|
|
245
|
-
const abort = useCallback(async () => {
|
|
246
|
-
abortController.current.abort();
|
|
247
|
-
await cleanup();
|
|
248
|
-
}, [cleanup]);
|
|
249
|
-
|
|
250
|
-
// Check if stream is active
|
|
251
|
-
const isActive = useCallback(() => {
|
|
252
|
-
return active.current;
|
|
253
|
-
}, []);
|
|
254
|
-
|
|
255
|
-
// Check if stream is paused
|
|
256
|
-
const isPaused = useCallback(() => {
|
|
257
|
-
return paused.current;
|
|
258
|
-
}, []);
|
|
259
|
-
|
|
260
|
-
// Cleanup on unmount
|
|
261
|
-
useEffect(() => {
|
|
262
|
-
return () => {
|
|
263
|
-
cleanup().catch(console.error);
|
|
264
|
-
};
|
|
265
|
-
}, [cleanup]);
|
|
266
|
-
|
|
267
|
-
return {
|
|
268
|
-
start,
|
|
269
|
-
pause,
|
|
270
|
-
resume,
|
|
271
|
-
abort,
|
|
272
|
-
isActive,
|
|
273
|
-
isPaused
|
|
274
|
-
};
|
|
275
|
-
};
|
|
276
|
-
|
|
277
|
-
export default useStreamController;
|