funda-ui 4.6.151 → 4.6.222
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.css +70 -13
- package/Chatbox/index.d.ts +1 -0
- package/Chatbox/index.js +351 -268
- package/lib/cjs/Chatbox/index.d.ts +1 -0
- package/lib/cjs/Chatbox/index.js +351 -268
- package/lib/css/Chatbox/index.css +70 -13
- package/lib/esm/Chatbox/PureLoader.tsx +4 -2
- package/lib/esm/Chatbox/TypingEffect.tsx +12 -41
- package/lib/esm/Chatbox/index.scss +92 -23
- package/lib/esm/Chatbox/index.tsx +66 -29
- package/lib/esm/Chatbox/utils/func.ts +52 -1
- package/lib/esm/Textarea/index.tsx +0 -2
- package/package.json +1 -1
|
@@ -1,24 +1,19 @@
|
|
|
1
1
|
/*=================== Chatbox (Loading) =================*/
|
|
2
2
|
.custom-chatbox-loader-container {
|
|
3
|
+
--custom-chatbox-loader-color: #b9caf7;
|
|
4
|
+
--custom-chatbox-loader-color2: #0d6efd;
|
|
3
5
|
width: 130px;
|
|
4
6
|
text-align: start;
|
|
5
7
|
}
|
|
6
8
|
.custom-chatbox-loader-container .custom-chatbox-loader {
|
|
7
9
|
height: 4px;
|
|
8
10
|
width: 100%;
|
|
9
|
-
--c: no-repeat linear-gradient(var(--
|
|
10
|
-
background: var(--c), var(--c),
|
|
11
|
+
--c: no-repeat linear-gradient(var(--custom-chatbox-loader-color2) 0 0);
|
|
12
|
+
background: var(--c), var(--c), var(--custom-chatbox-loader-color);
|
|
11
13
|
background-size: 60% 100%;
|
|
12
|
-
animation:
|
|
14
|
+
animation: loader-move 3s infinite;
|
|
13
15
|
}
|
|
14
|
-
|
|
15
|
-
.dark-mode .custom-chatbox-loader-container .custom-chatbox-loader,
|
|
16
|
-
[data-bs-theme=dark] .custom-chatbox-loader-container .custom-chatbox-loader {
|
|
17
|
-
--c: no-repeat linear-gradient(var(--bs-primary) 0 0);
|
|
18
|
-
background: var(--c), var(--c), #8692b5;
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
@keyframes cssAnim--loadermove {
|
|
16
|
+
@keyframes loader-move {
|
|
22
17
|
0% {
|
|
23
18
|
background-position: -150% 0, -150% 0;
|
|
24
19
|
}
|
|
@@ -29,6 +24,29 @@
|
|
|
29
24
|
background-position: 250% 0, 250% 0;
|
|
30
25
|
}
|
|
31
26
|
}
|
|
27
|
+
|
|
28
|
+
.custom-chatbox-mini-loader {
|
|
29
|
+
--custom-chatbox-miniloader-color: rgba(0,0,0,.5);
|
|
30
|
+
width: 15px;
|
|
31
|
+
height: 15px;
|
|
32
|
+
margin: 0.5rem;
|
|
33
|
+
margin-bottom: 0;
|
|
34
|
+
border: 3px dotted var(--custom-chatbox-miniloader-color);
|
|
35
|
+
border-radius: 50%;
|
|
36
|
+
display: inline-block;
|
|
37
|
+
position: relative;
|
|
38
|
+
box-sizing: border-box;
|
|
39
|
+
animation: mini-loader-spin 1s linear infinite;
|
|
40
|
+
}
|
|
41
|
+
@keyframes mini-loader-spin {
|
|
42
|
+
0% {
|
|
43
|
+
transform: rotate(0deg);
|
|
44
|
+
}
|
|
45
|
+
100% {
|
|
46
|
+
transform: rotate(360deg);
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
|
|
32
50
|
/*=================== Chatbox (Core) =================*/
|
|
33
51
|
.custom-chatbox-circle {
|
|
34
52
|
--custom-chatbox-circle-color: #5A5EB9;
|
|
@@ -115,6 +133,8 @@
|
|
|
115
133
|
--custom-chatbox-toolkit-btn-radius: 20px;
|
|
116
134
|
--custom-chatbox-questions-bg: #f5f5f5;
|
|
117
135
|
--custom-chatbox-questions-hover-bg: #e9e9e9;
|
|
136
|
+
--custom-chatbox-content-html-elem-border-color: #ddd;
|
|
137
|
+
--custom-chatbox-content-html-elem-bg: rgba(0,0,0,.05);
|
|
118
138
|
min-width: var(--custom-chatbox-w);
|
|
119
139
|
max-width: var(--custom-chatbox-w);
|
|
120
140
|
margin: auto;
|
|
@@ -142,6 +162,8 @@
|
|
|
142
162
|
padding: 0;
|
|
143
163
|
font-size: 0.75rem;
|
|
144
164
|
margin-bottom: 0.5rem;
|
|
165
|
+
background: var(--custom-chatbox-msg-bg);
|
|
166
|
+
padding: 0.5rem;
|
|
145
167
|
}
|
|
146
168
|
.custom-chatbox-container summary {
|
|
147
169
|
cursor: pointer;
|
|
@@ -171,7 +193,7 @@
|
|
|
171
193
|
font-size: 0.75rem;
|
|
172
194
|
}
|
|
173
195
|
.custom-chatbox-container .messages {
|
|
174
|
-
height: calc(100% -
|
|
196
|
+
height: calc(100% - 110px);
|
|
175
197
|
overflow-y: auto;
|
|
176
198
|
margin-bottom: 10px;
|
|
177
199
|
font-size: 13px;
|
|
@@ -216,6 +238,33 @@
|
|
|
216
238
|
margin-top: 0.3rem;
|
|
217
239
|
display: inline-block;
|
|
218
240
|
text-align: start;
|
|
241
|
+
/* Custom HTML Styles */
|
|
242
|
+
}
|
|
243
|
+
.custom-chatbox-container .messages .qa-content .table-container {
|
|
244
|
+
overflow-x: auto;
|
|
245
|
+
margin-bottom: 0.5rem;
|
|
246
|
+
}
|
|
247
|
+
.custom-chatbox-container .messages .qa-content .table-container::-webkit-scrollbar {
|
|
248
|
+
height: 10px;
|
|
249
|
+
}
|
|
250
|
+
.custom-chatbox-container .messages .qa-content .table-container::-webkit-scrollbar-thumb {
|
|
251
|
+
background: rgba(0, 0, 0, 0.2);
|
|
252
|
+
}
|
|
253
|
+
.custom-chatbox-container .messages .qa-content .table-container table {
|
|
254
|
+
width: 100%;
|
|
255
|
+
border-collapse: collapse;
|
|
256
|
+
border-radius: 0.35rem;
|
|
257
|
+
}
|
|
258
|
+
.custom-chatbox-container .messages .qa-content .table-container table thead {
|
|
259
|
+
background: var(--custom-chatbox-content-html-elem-bg);
|
|
260
|
+
}
|
|
261
|
+
.custom-chatbox-container .messages .qa-content .table-container table thead tr {
|
|
262
|
+
white-space: nowrap;
|
|
263
|
+
}
|
|
264
|
+
.custom-chatbox-container .messages .qa-content .table-container table th, .custom-chatbox-container .messages .qa-content .table-container table td {
|
|
265
|
+
padding: 0.25rem;
|
|
266
|
+
text-align: left;
|
|
267
|
+
border: 1px solid var(--custom-chatbox-content-html-elem-border-color);
|
|
219
268
|
}
|
|
220
269
|
.custom-chatbox-container .messages .request {
|
|
221
270
|
text-align: end;
|
|
@@ -232,6 +281,8 @@
|
|
|
232
281
|
}
|
|
233
282
|
.custom-chatbox-container .messages .reply .qa-content {
|
|
234
283
|
width: var(--custom-chatbox-content-w);
|
|
284
|
+
background: transparent;
|
|
285
|
+
padding-top: 0;
|
|
235
286
|
}
|
|
236
287
|
.custom-chatbox-container .msg-dotted-loader-container {
|
|
237
288
|
font-weight: normal;
|
|
@@ -373,6 +424,11 @@
|
|
|
373
424
|
}
|
|
374
425
|
.custom-chatbox-container .newchat-btn {
|
|
375
426
|
text-align: center;
|
|
427
|
+
position: absolute;
|
|
428
|
+
bottom: 95px;
|
|
429
|
+
left: 50%;
|
|
430
|
+
transform: translateX(-50%);
|
|
431
|
+
z-index: 1;
|
|
376
432
|
}
|
|
377
433
|
.custom-chatbox-container .newchat-btn > button {
|
|
378
434
|
padding: 3px 6px;
|
|
@@ -462,6 +518,7 @@
|
|
|
462
518
|
box-shadow: 0 -2px 10px rgba(0, 0, 0, 0.1);
|
|
463
519
|
margin-bottom: 10px;
|
|
464
520
|
max-height: 300px;
|
|
521
|
+
min-width: 120px;
|
|
465
522
|
overflow-y: auto;
|
|
466
523
|
animation: dropupAnimation 0.2s ease;
|
|
467
524
|
position: absolute;
|
|
@@ -489,7 +546,7 @@
|
|
|
489
546
|
.custom-chatbox-container .toolkit-select-wrapper .toolkit-select-option.cancel {
|
|
490
547
|
color: var(--custom-chatbox-gray-color);
|
|
491
548
|
}
|
|
492
|
-
.custom-chatbox-container .toolkit-select-wrapper .toolkit-select-option:hover {
|
|
549
|
+
.custom-chatbox-container .toolkit-select-wrapper .toolkit-select-option.selected:not(.cancel), .custom-chatbox-container .toolkit-select-wrapper .toolkit-select-option:hover {
|
|
493
550
|
background-color: var(--custom-chatbox-toolkit-opt-active-color);
|
|
494
551
|
}
|
|
495
552
|
.custom-chatbox-container .default-questions-title {
|
|
@@ -2,6 +2,7 @@ import React from "react";
|
|
|
2
2
|
|
|
3
3
|
|
|
4
4
|
type PureLoaderProps = {
|
|
5
|
+
prefix?: string;
|
|
5
6
|
txt?: React.ReactNode;
|
|
6
7
|
center?: boolean;
|
|
7
8
|
customClassName?: string;
|
|
@@ -12,6 +13,7 @@ type PureLoaderProps = {
|
|
|
12
13
|
const PureLoader = (props: PureLoaderProps) => {
|
|
13
14
|
|
|
14
15
|
const {
|
|
16
|
+
prefix = 'custom-',
|
|
15
17
|
txt,
|
|
16
18
|
center,
|
|
17
19
|
customClassName
|
|
@@ -21,11 +23,11 @@ const PureLoader = (props: PureLoaderProps) => {
|
|
|
21
23
|
return (
|
|
22
24
|
<>
|
|
23
25
|
|
|
24
|
-
<div className={
|
|
26
|
+
<div className={`${prefix}chatbox-loader-container ${customClassName || ''}`}>
|
|
25
27
|
<div className="row g-0 align-items-center">
|
|
26
28
|
<div className={center ? 'text-center' : ''}><small>{txt || txt === '' ? txt : 'Loading...'}</small></div>
|
|
27
29
|
<div>
|
|
28
|
-
<div className="
|
|
30
|
+
<div className="${prefix}chatbox-loader"></div>
|
|
29
31
|
</div>
|
|
30
32
|
</div>
|
|
31
33
|
</div>
|
|
@@ -1,57 +1,28 @@
|
|
|
1
1
|
import React, { useEffect, useState } from 'react';
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
// extract
|
|
4
|
+
import { extractHtmlTags } from './utils/func';
|
|
5
|
+
import type { HtmlTagPlaceholder } from './utils/func';
|
|
6
|
+
|
|
7
|
+
export interface TypingEffectProps {
|
|
4
8
|
content: string; // The content to display
|
|
5
9
|
speed: number; // Speed of typing in milliseconds
|
|
6
10
|
onComplete?: () => void; // Callback when typing is complete
|
|
7
11
|
onUpdate?: () => void; // Callback when typing
|
|
8
12
|
}
|
|
9
13
|
|
|
10
|
-
|
|
11
|
-
original: string;
|
|
12
|
-
placeholder: string;
|
|
13
|
-
type: 'img' | 'svg';
|
|
14
|
-
}
|
|
14
|
+
|
|
15
15
|
const TypingEffect: React.FC<TypingEffectProps> = ({ content, speed, onComplete, onUpdate }) => {
|
|
16
16
|
const [displayedContent, setDisplayedContent] = useState<string>('');
|
|
17
17
|
const [index, setIndex] = useState<number>(0);
|
|
18
|
-
const [
|
|
18
|
+
const [htmlTagPlaceholder, setHtmlTagPlaceholders] = useState<HtmlTagPlaceholder[]>([]);
|
|
19
19
|
const [processedContent, setProcessedContent] = useState<string>('');
|
|
20
20
|
|
|
21
21
|
// Extract and replace image tags
|
|
22
22
|
useEffect(() => {
|
|
23
|
-
const
|
|
24
|
-
const placeholders: ImagePlaceholder[] = [];
|
|
25
|
-
let processedHtml = html;
|
|
26
|
-
|
|
27
|
-
// <img>
|
|
28
|
-
processedHtml = processedHtml.replace(/<img[^>]*>/g, (match) => {
|
|
29
|
-
const placeholder = `[IMG_${placeholders.length}]`;
|
|
30
|
-
placeholders.push({
|
|
31
|
-
original: match,
|
|
32
|
-
placeholder,
|
|
33
|
-
type: 'img'
|
|
34
|
-
});
|
|
35
|
-
return placeholder;
|
|
36
|
-
});
|
|
37
|
-
|
|
38
|
-
// <svg>
|
|
39
|
-
processedHtml = processedHtml.replace(/<svg[^>]*>[\s\S]*?<\/svg>/g, (match) => {
|
|
40
|
-
const placeholder = `[SVG_${placeholders.length}]`;
|
|
41
|
-
placeholders.push({
|
|
42
|
-
original: match,
|
|
43
|
-
placeholder,
|
|
44
|
-
type: 'svg'
|
|
45
|
-
});
|
|
46
|
-
return placeholder;
|
|
47
|
-
});
|
|
48
|
-
|
|
49
|
-
return { processedHtml, placeholders };
|
|
50
|
-
};
|
|
51
|
-
|
|
52
|
-
const { processedHtml, placeholders } = extractImages(content);
|
|
23
|
+
const { processedHtml, placeholders } = extractHtmlTags(content);
|
|
53
24
|
setProcessedContent(processedHtml);
|
|
54
|
-
|
|
25
|
+
setHtmlTagPlaceholders(placeholders);
|
|
55
26
|
}, [content]);
|
|
56
27
|
|
|
57
28
|
// Handle typing effects
|
|
@@ -61,7 +32,7 @@ const TypingEffect: React.FC<TypingEffectProps> = ({ content, speed, onComplete,
|
|
|
61
32
|
let newContent = processedContent.substring(0, index + 1);
|
|
62
33
|
|
|
63
34
|
// Replace the completed placeholder
|
|
64
|
-
|
|
35
|
+
htmlTagPlaceholder.forEach(({ original, placeholder }) => {
|
|
65
36
|
if (newContent.includes(placeholder)) {
|
|
66
37
|
newContent = newContent.replace(placeholder, original);
|
|
67
38
|
}
|
|
@@ -77,9 +48,9 @@ const TypingEffect: React.FC<TypingEffectProps> = ({ content, speed, onComplete,
|
|
|
77
48
|
}, speed);
|
|
78
49
|
|
|
79
50
|
return () => clearInterval(timer);
|
|
80
|
-
}, [processedContent, index, speed, onComplete, onUpdate,
|
|
51
|
+
}, [processedContent, index, speed, onComplete, onUpdate, htmlTagPlaceholder]);
|
|
81
52
|
|
|
82
|
-
return <
|
|
53
|
+
return <div dangerouslySetInnerHTML={{ __html: displayedContent }} />;
|
|
83
54
|
};
|
|
84
55
|
|
|
85
56
|
export default TypingEffect;
|
|
@@ -2,49 +2,69 @@
|
|
|
2
2
|
|
|
3
3
|
/*=================== Chatbox (Loading) =================*/
|
|
4
4
|
.custom-chatbox-loader-container {
|
|
5
|
+
--custom-chatbox-loader-color: #b9caf7;
|
|
6
|
+
--custom-chatbox-loader-color2: #0d6efd;
|
|
7
|
+
|
|
8
|
+
|
|
5
9
|
width: 130px;
|
|
6
10
|
text-align: start;
|
|
7
11
|
|
|
8
12
|
.custom-chatbox-loader {
|
|
9
13
|
height: 4px;
|
|
10
14
|
width: 100%;
|
|
11
|
-
--c: no-repeat linear-gradient(var(--
|
|
12
|
-
background: var(--c), var(--c),
|
|
15
|
+
--c: no-repeat linear-gradient(var(--custom-chatbox-loader-color2) 0 0);
|
|
16
|
+
background: var(--c), var(--c), var(--custom-chatbox-loader-color);
|
|
13
17
|
background-size: 60% 100%;
|
|
14
|
-
animation:
|
|
18
|
+
animation: loader-move 3s infinite;
|
|
15
19
|
}
|
|
16
|
-
}
|
|
17
20
|
|
|
18
21
|
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
background:
|
|
22
|
+
@keyframes loader-move {
|
|
23
|
+
0% {
|
|
24
|
+
background-position: -150% 0, -150% 0
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
66% {
|
|
28
|
+
background-position: 250% 0, -150% 0
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
100% {
|
|
32
|
+
background-position: 250% 0, 250% 0
|
|
26
33
|
}
|
|
27
34
|
}
|
|
28
|
-
|
|
29
35
|
}
|
|
30
36
|
|
|
31
37
|
|
|
32
|
-
@keyframes cssAnim--loadermove {
|
|
33
|
-
0% {
|
|
34
|
-
background-position: -150% 0, -150% 0
|
|
35
|
-
}
|
|
36
38
|
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
39
|
+
.custom-chatbox-mini-loader {
|
|
40
|
+
--custom-chatbox-miniloader-color: rgba(0,0,0,.5);
|
|
41
|
+
|
|
42
|
+
width: 15px;
|
|
43
|
+
height: 15px;
|
|
44
|
+
margin: .5rem;
|
|
45
|
+
margin-bottom: 0;
|
|
46
|
+
border: 3px dotted var(--custom-chatbox-miniloader-color);
|
|
47
|
+
border-radius: 50%;
|
|
48
|
+
display: inline-block;
|
|
49
|
+
position: relative;
|
|
50
|
+
box-sizing: border-box;
|
|
51
|
+
animation: mini-loader-spin 1s linear infinite;
|
|
52
|
+
|
|
53
|
+
@keyframes mini-loader-spin {
|
|
54
|
+
0% {
|
|
55
|
+
transform: rotate(0deg);
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
100% {
|
|
59
|
+
transform: rotate(360deg);
|
|
60
|
+
}
|
|
40
61
|
|
|
41
|
-
100% {
|
|
42
|
-
background-position: 250% 0, 250% 0
|
|
43
62
|
}
|
|
44
63
|
}
|
|
45
64
|
|
|
46
65
|
|
|
47
66
|
|
|
67
|
+
|
|
48
68
|
/*=================== Chatbox (Core) =================*/
|
|
49
69
|
|
|
50
70
|
.custom-chatbox-circle {
|
|
@@ -144,7 +164,8 @@
|
|
|
144
164
|
--custom-chatbox-toolkit-btn-radius: 20px;
|
|
145
165
|
--custom-chatbox-questions-bg: #f5f5f5;
|
|
146
166
|
--custom-chatbox-questions-hover-bg: #e9e9e9;
|
|
147
|
-
|
|
167
|
+
--custom-chatbox-content-html-elem-border-color: #ddd;
|
|
168
|
+
--custom-chatbox-content-html-elem-bg: rgba(0,0,0,.05);
|
|
148
169
|
|
|
149
170
|
min-width: var(--custom-chatbox-w);
|
|
150
171
|
max-width: var(--custom-chatbox-w);
|
|
@@ -165,6 +186,8 @@
|
|
|
165
186
|
padding: 0;
|
|
166
187
|
font-size: 0.75rem;
|
|
167
188
|
margin-bottom: .5rem;
|
|
189
|
+
background: var(--custom-chatbox-msg-bg);
|
|
190
|
+
padding: .5rem;
|
|
168
191
|
}
|
|
169
192
|
|
|
170
193
|
summary {
|
|
@@ -201,7 +224,7 @@
|
|
|
201
224
|
|
|
202
225
|
/* message list */
|
|
203
226
|
.messages {
|
|
204
|
-
height: calc(100% -
|
|
227
|
+
height: calc(100% - 110px);
|
|
205
228
|
overflow-y: auto;
|
|
206
229
|
margin-bottom: 10px;
|
|
207
230
|
font-size: 13px;
|
|
@@ -254,6 +277,43 @@
|
|
|
254
277
|
margin-top: .3rem;
|
|
255
278
|
display: inline-block;
|
|
256
279
|
text-align: start;
|
|
280
|
+
|
|
281
|
+
|
|
282
|
+
/* Custom HTML Styles */
|
|
283
|
+
.table-container {
|
|
284
|
+
overflow-x: auto;
|
|
285
|
+
margin-bottom: .5rem;
|
|
286
|
+
|
|
287
|
+
&::-webkit-scrollbar {
|
|
288
|
+
height: 10px;
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
&::-webkit-scrollbar-thumb {
|
|
292
|
+
background: rgba(0, 0, 0, 0.2);
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
table {
|
|
296
|
+
width: 100%;
|
|
297
|
+
border-collapse: collapse;
|
|
298
|
+
border-radius: 0.35rem;
|
|
299
|
+
|
|
300
|
+
|
|
301
|
+
thead {
|
|
302
|
+
background: var(--custom-chatbox-content-html-elem-bg);
|
|
303
|
+
|
|
304
|
+
tr {
|
|
305
|
+
white-space: nowrap;
|
|
306
|
+
}
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
th, td {
|
|
310
|
+
padding: .25rem;
|
|
311
|
+
text-align: left;
|
|
312
|
+
border: 1px solid var(--custom-chatbox-content-html-elem-border-color);
|
|
313
|
+
}
|
|
314
|
+
}
|
|
315
|
+
}
|
|
316
|
+
|
|
257
317
|
}
|
|
258
318
|
|
|
259
319
|
|
|
@@ -275,6 +335,8 @@
|
|
|
275
335
|
|
|
276
336
|
.qa-content {
|
|
277
337
|
width: var(--custom-chatbox-content-w);
|
|
338
|
+
background: transparent;
|
|
339
|
+
padding-top: 0;
|
|
278
340
|
}
|
|
279
341
|
}
|
|
280
342
|
|
|
@@ -456,6 +518,11 @@
|
|
|
456
518
|
/* new chat button */
|
|
457
519
|
.newchat-btn {
|
|
458
520
|
text-align: center;
|
|
521
|
+
position: absolute;
|
|
522
|
+
bottom: 95px;
|
|
523
|
+
left: 50%;
|
|
524
|
+
transform: translateX(-50%);
|
|
525
|
+
z-index: 1;
|
|
459
526
|
|
|
460
527
|
> button {
|
|
461
528
|
padding: 3px 6px;
|
|
@@ -572,6 +639,7 @@
|
|
|
572
639
|
box-shadow: 0 -2px 10px rgba(0, 0, 0, 0.1);
|
|
573
640
|
margin-bottom: 10px;
|
|
574
641
|
max-height: 300px;
|
|
642
|
+
min-width: 120px;
|
|
575
643
|
overflow-y: auto;
|
|
576
644
|
animation: dropupAnimation 0.2s ease;
|
|
577
645
|
|
|
@@ -606,6 +674,7 @@
|
|
|
606
674
|
color: var(--custom-chatbox-gray-color);
|
|
607
675
|
}
|
|
608
676
|
|
|
677
|
+
&.selected:not(.cancel),
|
|
609
678
|
&:hover {
|
|
610
679
|
background-color: var(--custom-chatbox-toolkit-opt-active-color);
|
|
611
680
|
}
|
|
@@ -12,7 +12,6 @@ import useClickOutside from 'funda-utils/dist/cjs/useClickOutside';
|
|
|
12
12
|
import { htmlEncode } from 'funda-utils/dist/cjs/sanitize';
|
|
13
13
|
|
|
14
14
|
|
|
15
|
-
|
|
16
15
|
// loader
|
|
17
16
|
import PureLoader from './PureLoader';
|
|
18
17
|
import TypingEffect from "./TypingEffect";
|
|
@@ -51,6 +50,7 @@ export interface FloatingButton {
|
|
|
51
50
|
value: string;
|
|
52
51
|
onClick: string;
|
|
53
52
|
isSelect?: boolean; // Mark whether it is a drop-down selection button
|
|
53
|
+
dynamicOptions?: boolean; // Mark whether to use dynamic options
|
|
54
54
|
[key: string]: any; // Allows dynamic `onSelect__<number>` attributes, such as `onSelect__1`, `onSelect__2`, ...
|
|
55
55
|
}
|
|
56
56
|
|
|
@@ -201,8 +201,10 @@ const Chatbox = (props: ChatboxProps) => {
|
|
|
201
201
|
setShow(false);
|
|
202
202
|
},
|
|
203
203
|
clearData: () => {
|
|
204
|
-
|
|
204
|
+
// Update both the conversation history and displayed messages
|
|
205
205
|
conversationHistory.current = [];
|
|
206
|
+
setMsgList([]);
|
|
207
|
+
|
|
206
208
|
},
|
|
207
209
|
sendMsg: () => {
|
|
208
210
|
handleClickSafe();
|
|
@@ -214,6 +216,11 @@ const Chatbox = (props: ChatboxProps) => {
|
|
|
214
216
|
conversationHistory.current = conversationHistory.current.slice(-maxLength);
|
|
215
217
|
}
|
|
216
218
|
},
|
|
219
|
+
setHistory: (messages: MessageDetail[]) => {
|
|
220
|
+
// Update both the conversation history and displayed messages
|
|
221
|
+
conversationHistory.current = [...messages];
|
|
222
|
+
setMsgList([...messages]);
|
|
223
|
+
},
|
|
217
224
|
setVal: (v: string) => {
|
|
218
225
|
if (inputContentRef.current) inputContentRef.current.set(v);
|
|
219
226
|
},
|
|
@@ -427,16 +434,28 @@ const Chatbox = (props: ChatboxProps) => {
|
|
|
427
434
|
return newState;
|
|
428
435
|
});
|
|
429
436
|
};
|
|
430
|
-
const executeButtonAction = (actionStr: string, buttonId: string, buttonElement: HTMLButtonElement) => {
|
|
437
|
+
const executeButtonAction = async (actionStr: string, buttonId: string, buttonElement: HTMLButtonElement) => {
|
|
431
438
|
try {
|
|
432
|
-
// Create a new function to execute
|
|
433
439
|
const actionFn = new Function('method', 'isActive', 'button', actionStr);
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
440
|
+
|
|
441
|
+
// !!!REQUIRED "await"
|
|
442
|
+
// "customMethods" may be asynchronous
|
|
443
|
+
const result = await actionFn(exposedMethods(), !activeButtons[buttonId], buttonElement);
|
|
444
|
+
|
|
445
|
+
// If the returned result is an array, it is a dynamic option
|
|
446
|
+
if (Array.isArray(result) && Object.keys(dynamicOptions).length === 0) {
|
|
447
|
+
const options: FloatingButtonSelectOption[] = result.map(item => {
|
|
448
|
+
const [key, value] = Object.entries(item)[0];
|
|
449
|
+
const [label, val, onClick] = (value as string).split('{#}').map((s: string) => s.trim());
|
|
450
|
+
return { label, value: val, onClick };
|
|
451
|
+
});
|
|
452
|
+
|
|
453
|
+
// Update dynamic options
|
|
454
|
+
setDynamicOptions(prev => ({
|
|
455
|
+
...prev,
|
|
456
|
+
[buttonId]: options
|
|
457
|
+
}));
|
|
438
458
|
}
|
|
439
|
-
*/
|
|
440
459
|
|
|
441
460
|
// Update the button status
|
|
442
461
|
const newState = !activeButtons[buttonId];
|
|
@@ -445,17 +464,28 @@ const Chatbox = (props: ChatboxProps) => {
|
|
|
445
464
|
[buttonId]: newState
|
|
446
465
|
}));
|
|
447
466
|
|
|
448
|
-
return
|
|
449
|
-
|
|
450
|
-
|
|
467
|
+
return result;
|
|
451
468
|
} catch (error) {
|
|
452
469
|
console.error('Error executing button action:', error);
|
|
453
470
|
}
|
|
454
471
|
};
|
|
472
|
+
|
|
473
|
+
|
|
455
474
|
|
|
456
475
|
// options
|
|
457
476
|
const [selectedOpt, setSelectedOpt] = useState<Record<string, string | number>>({});
|
|
458
|
-
|
|
477
|
+
// Store dynamic options
|
|
478
|
+
const [dynamicOptions, setDynamicOptions] = useState<Record<string, FloatingButtonSelectOption[]>>({});
|
|
479
|
+
|
|
480
|
+
const getButtonOptions = (btn: FloatingButton, buttonId: string): FloatingButtonSelectOption[] => {
|
|
481
|
+
// If you are using the dynamic option and already have a cache, return the option for caching
|
|
482
|
+
//---------
|
|
483
|
+
if (btn.dynamicOptions && dynamicOptions[buttonId]) {
|
|
484
|
+
return dynamicOptions[buttonId];
|
|
485
|
+
}
|
|
486
|
+
|
|
487
|
+
// Use the static option from "props"
|
|
488
|
+
//---------
|
|
459
489
|
const options: FloatingButtonSelectOption[] = [];
|
|
460
490
|
let index = 1;
|
|
461
491
|
|
|
@@ -1431,7 +1461,7 @@ const Chatbox = (props: ChatboxProps) => {
|
|
|
1431
1461
|
|
|
1432
1462
|
|
|
1433
1463
|
{/**------------- SEND LOADING -------------*/}
|
|
1434
|
-
{args().sendLoading ? <div className="loading"><div style={{ display: loading ? 'block' : 'none' }}><PureLoader customClassName="w-100" txt="" /></div></div> : null}
|
|
1464
|
+
{args().sendLoading ? <div className="loading"><div style={{ display: loading ? 'block' : 'none' }}><PureLoader prefix={args().prefix} customClassName="w-100" txt="" /></div></div> : null}
|
|
1435
1465
|
{/**------------- /SEND LOADING -------------*/}
|
|
1436
1466
|
|
|
1437
1467
|
|
|
@@ -1443,8 +1473,8 @@ const Chatbox = (props: ChatboxProps) => {
|
|
|
1443
1473
|
const isActive = activeButtons[_id];
|
|
1444
1474
|
|
|
1445
1475
|
if (btn.isSelect) {
|
|
1446
|
-
const options = getButtonOptions(btn);
|
|
1447
|
-
|
|
1476
|
+
const options = getButtonOptions(btn, _id);
|
|
1477
|
+
|
|
1448
1478
|
return (
|
|
1449
1479
|
<div key={index} className="toolkit-select-wrapper">
|
|
1450
1480
|
<button
|
|
@@ -1456,6 +1486,9 @@ const Chatbox = (props: ChatboxProps) => {
|
|
|
1456
1486
|
...prev,
|
|
1457
1487
|
[_id]: !prev[_id]
|
|
1458
1488
|
}));
|
|
1489
|
+
|
|
1490
|
+
//
|
|
1491
|
+
executeButtonAction(btn.onClick, _id, e.currentTarget);
|
|
1459
1492
|
}}
|
|
1460
1493
|
>
|
|
1461
1494
|
<span dangerouslySetInnerHTML={{
|
|
@@ -1474,18 +1507,23 @@ const Chatbox = (props: ChatboxProps) => {
|
|
|
1474
1507
|
</svg></span>
|
|
1475
1508
|
</button>
|
|
1476
1509
|
|
|
1477
|
-
|
|
1478
|
-
|
|
1510
|
+
{/* OPTIONS */}
|
|
1479
1511
|
<div className={`toolkit-select-options ${isActive ? 'active' : ''}`}>
|
|
1480
|
-
|
|
1481
|
-
|
|
1482
|
-
|
|
1483
|
-
|
|
1484
|
-
|
|
1485
|
-
|
|
1486
|
-
|
|
1487
|
-
|
|
1488
|
-
|
|
1512
|
+
|
|
1513
|
+
{options.length > 0 ? <>
|
|
1514
|
+
{options.map((option: FloatingButtonSelectOption, optIndex: number) => (
|
|
1515
|
+
<div
|
|
1516
|
+
key={optIndex}
|
|
1517
|
+
className={`toolkit-select-option ${option.value || ''} ${selectedOpt.curIndex === optIndex ? 'selected' : ''}`}
|
|
1518
|
+
onClick={() => handleExecuteButtonSelect(_id, option, optIndex, option.value)}
|
|
1519
|
+
>
|
|
1520
|
+
<span dangerouslySetInnerHTML={{ __html: option.label }}></span>
|
|
1521
|
+
</div>
|
|
1522
|
+
))}
|
|
1523
|
+
</> : <>
|
|
1524
|
+
<div className={`${args().prefix || 'custom-'}chatbox-mini-loader`}></div>
|
|
1525
|
+
</>}
|
|
1526
|
+
|
|
1489
1527
|
</div>
|
|
1490
1528
|
</div>
|
|
1491
1529
|
);
|
|
@@ -1497,8 +1535,7 @@ const Chatbox = (props: ChatboxProps) => {
|
|
|
1497
1535
|
key={index}
|
|
1498
1536
|
id={_id}
|
|
1499
1537
|
className={`${btn.value || ''} ${isActive ? 'active' : ''}`}
|
|
1500
|
-
onClick={(e: React.MouseEvent<HTMLButtonElement>) =>
|
|
1501
|
-
executeButtonAction(btn.onClick, _id, e.currentTarget)}
|
|
1538
|
+
onClick={(e: React.MouseEvent<HTMLButtonElement>) => executeButtonAction(btn.onClick, _id, e.currentTarget)}
|
|
1502
1539
|
>
|
|
1503
1540
|
<span dangerouslySetInnerHTML={{ __html: btn.label }}></span>
|
|
1504
1541
|
</button>
|