funda-ui 4.6.101 → 4.6.151
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 +25 -1
- package/Chatbox/index.d.ts +7 -0
- package/Chatbox/index.js +279 -133
- package/Date/index.js +53 -47
- package/Select/index.d.ts +4 -4
- package/TagInput/index.d.ts +6 -0
- package/TagInput/index.js +6 -3
- package/Textarea/index.js +46 -46
- package/Utils/sanitize.d.ts +14 -0
- package/Utils/sanitize.js +87 -0
- package/Utils/useAutosizeTextArea.js +46 -46
- package/lib/cjs/Chatbox/index.d.ts +7 -0
- package/lib/cjs/Chatbox/index.js +279 -133
- package/lib/cjs/Date/index.js +53 -47
- package/lib/cjs/Select/index.d.ts +4 -4
- package/lib/cjs/TagInput/index.d.ts +6 -0
- package/lib/cjs/TagInput/index.js +6 -3
- package/lib/cjs/Textarea/index.js +46 -46
- package/lib/cjs/Utils/sanitize.d.ts +14 -0
- package/lib/cjs/Utils/sanitize.js +87 -0
- package/lib/cjs/Utils/useAutosizeTextArea.js +46 -46
- package/lib/css/Chatbox/index.css +25 -1
- package/lib/esm/Chatbox/index.scss +33 -2
- package/lib/esm/Chatbox/index.tsx +70 -8
- package/lib/esm/Chatbox/utils/func.ts +0 -54
- package/lib/esm/Date/index.tsx +60 -43
- package/lib/esm/Input/index.tsx +1 -0
- package/lib/esm/Select/index.tsx +4 -5
- package/lib/esm/TagInput/index.tsx +30 -10
- package/lib/esm/Textarea/index.tsx +1 -0
- package/lib/esm/Utils/hooks/useAutosizeTextArea.tsx +47 -49
- package/lib/esm/Utils/libs/sanitize.ts +55 -0
- package/package.json +1 -1
|
@@ -9,6 +9,8 @@ import useComId from 'funda-utils/dist/cjs/useComId';
|
|
|
9
9
|
import useDebounce from 'funda-utils/dist/cjs/useDebounce';
|
|
10
10
|
import useThrottle from 'funda-utils/dist/cjs/useThrottle';
|
|
11
11
|
import useClickOutside from 'funda-utils/dist/cjs/useClickOutside';
|
|
12
|
+
import { htmlEncode } from 'funda-utils/dist/cjs/sanitize';
|
|
13
|
+
|
|
12
14
|
|
|
13
15
|
|
|
14
16
|
// loader
|
|
@@ -20,8 +22,7 @@ import {
|
|
|
20
22
|
formatLatestDisplayContent,
|
|
21
23
|
formatName,
|
|
22
24
|
fixHtmlTags,
|
|
23
|
-
isStreamResponse
|
|
24
|
-
htmlEncode
|
|
25
|
+
isStreamResponse
|
|
25
26
|
} from './utils/func';
|
|
26
27
|
|
|
27
28
|
import useStreamController from './useStreamController';
|
|
@@ -38,6 +39,13 @@ export type MessageDetail = {
|
|
|
38
39
|
tag: string; // such as '[reply]'
|
|
39
40
|
};
|
|
40
41
|
|
|
42
|
+
|
|
43
|
+
export type QuestionData = {
|
|
44
|
+
title: string;
|
|
45
|
+
list: Array<string>;
|
|
46
|
+
};
|
|
47
|
+
|
|
48
|
+
|
|
41
49
|
export interface FloatingButton {
|
|
42
50
|
label: string; // HTML string
|
|
43
51
|
value: string;
|
|
@@ -77,6 +85,7 @@ export type CustomRequestFunction = (
|
|
|
77
85
|
|
|
78
86
|
export type ChatboxProps = {
|
|
79
87
|
debug?: boolean;
|
|
88
|
+
defaultRows?: number;
|
|
80
89
|
prefix?: string;
|
|
81
90
|
contentRef?: React.RefObject<any>;
|
|
82
91
|
model?: string;
|
|
@@ -104,10 +113,12 @@ export type ChatboxProps = {
|
|
|
104
113
|
toolkitButtons?: FloatingButton[];
|
|
105
114
|
newChatButton?: FloatingButton;
|
|
106
115
|
customMethods?: CustomMethod[]; // [{"name": "method1", "func": "() => { console.log('test'); }"}, ...]
|
|
116
|
+
defaultQuestions?: QuestionData;
|
|
107
117
|
customRequest?: CustomRequestFunction;
|
|
108
118
|
renderParser?: (input: string) => Promise<string>;
|
|
109
119
|
requestBodyFormatter?: (body: any, contextData: Record<string, any>, conversationHistory: MessageDetail[]) => Promise<Record<string, any>>;
|
|
110
120
|
nameFormatter?: (input: string) => string;
|
|
121
|
+
onQuestionClick?: (text: string, methods: Record<string, Function>) => void;
|
|
111
122
|
onInputChange?: (controlRef: React.RefObject<any>, val: string) => any;
|
|
112
123
|
onInputCallback?: (input: string) => Promise<string>;
|
|
113
124
|
onChunk?: (controlRef: React.RefObject<any>, lastContent: string, conversationHistory: MessageDetail[]) => any;
|
|
@@ -253,6 +264,7 @@ const Chatbox = (props: ChatboxProps) => {
|
|
|
253
264
|
|
|
254
265
|
const {
|
|
255
266
|
debug,
|
|
267
|
+
defaultRows,
|
|
256
268
|
prefix,
|
|
257
269
|
contentRef,
|
|
258
270
|
model,
|
|
@@ -276,6 +288,7 @@ const Chatbox = (props: ChatboxProps) => {
|
|
|
276
288
|
newChatButton,
|
|
277
289
|
maxHistoryLength,
|
|
278
290
|
customRequest,
|
|
291
|
+
onQuestionClick,
|
|
279
292
|
renderParser,
|
|
280
293
|
requestBodyFormatter,
|
|
281
294
|
nameFormatter,
|
|
@@ -328,6 +341,7 @@ const Chatbox = (props: ChatboxProps) => {
|
|
|
328
341
|
|
|
329
342
|
return {
|
|
330
343
|
debug,
|
|
344
|
+
defaultRows,
|
|
331
345
|
prefix,
|
|
332
346
|
contentRef,
|
|
333
347
|
model,
|
|
@@ -348,6 +362,7 @@ const Chatbox = (props: ChatboxProps) => {
|
|
|
348
362
|
toolkitButtons,
|
|
349
363
|
newChatButton,
|
|
350
364
|
customRequest,
|
|
365
|
+
onQuestionClick,
|
|
351
366
|
renderParser,
|
|
352
367
|
requestBodyFormatter,
|
|
353
368
|
nameFormatter,
|
|
@@ -357,6 +372,7 @@ const Chatbox = (props: ChatboxProps) => {
|
|
|
357
372
|
onComplete,
|
|
358
373
|
|
|
359
374
|
//
|
|
375
|
+
defaultQuestionsRes: questions,
|
|
360
376
|
latestContextData,
|
|
361
377
|
questionNameRes: _questionName,
|
|
362
378
|
answerNameRes: _answerName,
|
|
@@ -371,6 +387,28 @@ const Chatbox = (props: ChatboxProps) => {
|
|
|
371
387
|
}
|
|
372
388
|
|
|
373
389
|
|
|
390
|
+
|
|
391
|
+
//================================================================
|
|
392
|
+
// Custom Questions
|
|
393
|
+
//================================================================
|
|
394
|
+
const [questions, setQuestions] = useState<QuestionData | undefined>(props.defaultQuestions);
|
|
395
|
+
useEffect(() => {
|
|
396
|
+
if (props.defaultQuestions) {
|
|
397
|
+
setQuestions(props.defaultQuestions);
|
|
398
|
+
}
|
|
399
|
+
}, [props.defaultQuestions]);
|
|
400
|
+
const hasQuestion = () => {
|
|
401
|
+
return args().defaultQuestionsRes && (args().defaultQuestionsRes as QuestionData).list.length > 0;
|
|
402
|
+
};
|
|
403
|
+
const handleQuestionClick = (text: string) => {
|
|
404
|
+
if (inputContentRef.current) {
|
|
405
|
+
inputContentRef.current.set(text);
|
|
406
|
+
}
|
|
407
|
+
|
|
408
|
+
args().onQuestionClick?.(text, exposedMethods());
|
|
409
|
+
};
|
|
410
|
+
|
|
411
|
+
|
|
374
412
|
//================================================================
|
|
375
413
|
// Custom buttons
|
|
376
414
|
//================================================================
|
|
@@ -380,7 +418,7 @@ const Chatbox = (props: ChatboxProps) => {
|
|
|
380
418
|
setActiveButtons(prev => {
|
|
381
419
|
const newState = { ...prev };
|
|
382
420
|
// Turn off only buttons with "isSelect"
|
|
383
|
-
args().toolkitButtons?.forEach((btn, index) => {
|
|
421
|
+
args().toolkitButtons?.forEach((btn: FloatingButton, index: number) => {
|
|
384
422
|
if (btn.isSelect) {
|
|
385
423
|
const _id = `${args().prefix || 'custom-'}chatbox-btn-tools-${chatId}${index}`;
|
|
386
424
|
newState[_id] = false;
|
|
@@ -1120,7 +1158,7 @@ const Chatbox = (props: ChatboxProps) => {
|
|
|
1120
1158
|
{/**------------- NO DATA -------------*/}
|
|
1121
1159
|
{msgList.length === 0 ? <>
|
|
1122
1160
|
|
|
1123
|
-
<div className=
|
|
1161
|
+
<div className={`d-flex flex-column align-items-center justify-content-center ${hasQuestion() ? '' : 'h-50'}`}>
|
|
1124
1162
|
<p>
|
|
1125
1163
|
<svg width="70px" height="70px" viewBox="0 0 24 24" fill="none">
|
|
1126
1164
|
<path d="M12 22C17.5228 22 22 17.5228 22 12C22 6.47715 17.5228 2 12 2C6.47715 2 2 6.47715 2 12C2 13.5997 2.37562 15.1116 3.04346 16.4525C3.22094 16.8088 3.28001 17.2161 3.17712 17.6006L2.58151 19.8267C2.32295 20.793 3.20701 21.677 4.17335 21.4185L6.39939 20.8229C6.78393 20.72 7.19121 20.7791 7.54753 20.9565C8.88837 21.6244 10.4003 22 12 22Z" stroke="#858297" strokeWidth="1.5" />
|
|
@@ -1130,7 +1168,26 @@ const Chatbox = (props: ChatboxProps) => {
|
|
|
1130
1168
|
|
|
1131
1169
|
</p>
|
|
1132
1170
|
<p className="text-primary" dangerouslySetInnerHTML={{ __html: `${args().noDataPlaceholder}` }}></p>
|
|
1171
|
+
|
|
1172
|
+
{/** DEFAULT QUESTIONS */}
|
|
1173
|
+
{hasQuestion() && (
|
|
1174
|
+
<div className="default-questions">
|
|
1175
|
+
<div className="default-questions-title" dangerouslySetInnerHTML={{ __html: `${(args().defaultQuestionsRes as QuestionData).title}` }}></div>
|
|
1176
|
+
{(args().defaultQuestionsRes as QuestionData).list?.map((question: string, index: number) => (
|
|
1177
|
+
<div
|
|
1178
|
+
key={index}
|
|
1179
|
+
className="default-question-item"
|
|
1180
|
+
onClick={() => handleQuestionClick(question)}
|
|
1181
|
+
dangerouslySetInnerHTML={{ __html: `${question}` }}
|
|
1182
|
+
/>
|
|
1183
|
+
))}
|
|
1184
|
+
</div>
|
|
1185
|
+
)}
|
|
1186
|
+
{/** /DEFAULT QUESTIONS */}
|
|
1187
|
+
|
|
1133
1188
|
</div>
|
|
1189
|
+
|
|
1190
|
+
|
|
1134
1191
|
</> : null}
|
|
1135
1192
|
{/**------------- /NO DATA -------------*/}
|
|
1136
1193
|
|
|
@@ -1300,7 +1357,6 @@ const Chatbox = (props: ChatboxProps) => {
|
|
|
1300
1357
|
{/**------------- CONTROL AREA -------------*/}
|
|
1301
1358
|
<div className="msgcontrol">
|
|
1302
1359
|
|
|
1303
|
-
|
|
1304
1360
|
<Textarea
|
|
1305
1361
|
ref={msInput}
|
|
1306
1362
|
contentRef={inputContentRef}
|
|
@@ -1309,15 +1365,21 @@ const Chatbox = (props: ChatboxProps) => {
|
|
|
1309
1365
|
placeholder={args().placeholder}
|
|
1310
1366
|
disabled={loading ? true : false}
|
|
1311
1367
|
onKeyDown={(event: React.KeyboardEvent) => {
|
|
1312
|
-
|
|
1313
|
-
|
|
1368
|
+
// line breaks
|
|
1369
|
+
if (event.key === 'Enter' && (event.ctrlKey || event.metaKey)) {
|
|
1370
|
+
return;
|
|
1371
|
+
}
|
|
1372
|
+
|
|
1373
|
+
if (event.key === 'Enter' && !event.shiftKey && !event.ctrlKey && !event.metaKey) {
|
|
1374
|
+
event.preventDefault(); // Prevent line breaks
|
|
1314
1375
|
handleClickSafe();
|
|
1315
1376
|
}
|
|
1377
|
+
|
|
1316
1378
|
}}
|
|
1317
1379
|
onChange={(e) => {
|
|
1318
1380
|
args().onInputChange?.(inputContentRef.current, e.target.value);
|
|
1319
1381
|
}}
|
|
1320
|
-
rows={3}
|
|
1382
|
+
rows={args().defaultRows || 3}
|
|
1321
1383
|
autoSize
|
|
1322
1384
|
autoSizeMaxHeight={200}
|
|
1323
1385
|
/>
|
|
@@ -127,57 +127,3 @@ export function isStreamResponse(response: Response): boolean {
|
|
|
127
127
|
return response.body instanceof ReadableStream;
|
|
128
128
|
};
|
|
129
129
|
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
/**
|
|
133
|
-
* HTML entities encode
|
|
134
|
-
*
|
|
135
|
-
* @param {String} str Input text
|
|
136
|
-
* @return {String} Filtered text
|
|
137
|
-
*/
|
|
138
|
-
export function htmlEncode(str) {
|
|
139
|
-
|
|
140
|
-
return str.replace(/[&<>'"]/g, tag => ({
|
|
141
|
-
'&': '&',
|
|
142
|
-
'<': '<',
|
|
143
|
-
'>': '>',
|
|
144
|
-
"'": ''',
|
|
145
|
-
'"': '"'
|
|
146
|
-
}[tag]));
|
|
147
|
-
|
|
148
|
-
}
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
/**
|
|
152
|
-
* HTML entities decode
|
|
153
|
-
*
|
|
154
|
-
* @param {String} str Input text
|
|
155
|
-
* @return {String} Filtered text
|
|
156
|
-
*/
|
|
157
|
-
export function htmlDecode(str) {
|
|
158
|
-
|
|
159
|
-
let res = '';
|
|
160
|
-
const entities = [
|
|
161
|
-
['amp', '&'],
|
|
162
|
-
['apos', '\''],
|
|
163
|
-
['#x27', '\''],
|
|
164
|
-
['#x2F', '/'],
|
|
165
|
-
['#39', '\''],
|
|
166
|
-
['#47', '/'],
|
|
167
|
-
['lt', '<'],
|
|
168
|
-
['gt', '>'],
|
|
169
|
-
['nbsp', ' '],
|
|
170
|
-
['quot', '"'],
|
|
171
|
-
['#60', '<'],
|
|
172
|
-
['#62', '>']
|
|
173
|
-
];
|
|
174
|
-
|
|
175
|
-
for (let i = 0, max = entities.length; i < max; i++) {
|
|
176
|
-
str = str.replace(new RegExp('&' + entities[i][0] + ';', 'g'), entities[i][1]);
|
|
177
|
-
}
|
|
178
|
-
res = str;
|
|
179
|
-
|
|
180
|
-
return res;
|
|
181
|
-
|
|
182
|
-
}
|
|
183
|
-
|
package/lib/esm/Date/index.tsx
CHANGED
|
@@ -28,6 +28,8 @@ import {
|
|
|
28
28
|
import { isNumeric } from 'funda-utils/dist/cjs/math';
|
|
29
29
|
import { clsWrite, combinedCls } from 'funda-utils/dist/cjs/cls';
|
|
30
30
|
|
|
31
|
+
|
|
32
|
+
|
|
31
33
|
import Calendar from './Calendar';
|
|
32
34
|
|
|
33
35
|
|
|
@@ -196,6 +198,9 @@ const Date = forwardRef((props: DateProps, externalRef: any) => {
|
|
|
196
198
|
return typeof s === 'undefined' || s === null || s === 'null' || s === '';
|
|
197
199
|
};
|
|
198
200
|
|
|
201
|
+
const propExist = (p: any) => {
|
|
202
|
+
return typeof p !== 'undefined' && p !== null && p !== '';
|
|
203
|
+
};
|
|
199
204
|
|
|
200
205
|
|
|
201
206
|
|
|
@@ -901,7 +906,52 @@ const Date = forwardRef((props: DateProps, externalRef: any) => {
|
|
|
901
906
|
return [_res, v]
|
|
902
907
|
|
|
903
908
|
}
|
|
904
|
-
|
|
909
|
+
|
|
910
|
+
function tools() {
|
|
911
|
+
return <span className={combinedCls(
|
|
912
|
+
'date2d__control-tools',
|
|
913
|
+
{
|
|
914
|
+
'date2d__control-tools--hover-show-tools': SHOW_TOOLS_ENABLED
|
|
915
|
+
}
|
|
916
|
+
|
|
917
|
+
)}>
|
|
918
|
+
|
|
919
|
+
<a
|
|
920
|
+
tabIndex={-1}
|
|
921
|
+
href="#"
|
|
922
|
+
className={combinedCls(
|
|
923
|
+
'date2d__control-tools__close',
|
|
924
|
+
{
|
|
925
|
+
'd-none': HIDE_CLEAR_BTN_ENABLED || !dateDefaultValueExist
|
|
926
|
+
}
|
|
927
|
+
)} onClick={(e: React.MouseEvent) => {
|
|
928
|
+
e.preventDefault();
|
|
929
|
+
e.stopPropagation(); // Avoid triggering pop-ups
|
|
930
|
+
|
|
931
|
+
clearAll();
|
|
932
|
+
onClear?.(getFullTimeData(''));
|
|
933
|
+
}}
|
|
934
|
+
><svg width="12px" height="12px" viewBox="0 0 1024 1024"><path fill="#000" d="M195.2 195.2a64 64 0 0 1 90.496 0L512 421.504 738.304 195.2a64 64 0 0 1 90.496 90.496L602.496 512 828.8 738.304a64 64 0 0 1-90.496 90.496L512 602.496 285.696 828.8a64 64 0 0 1-90.496-90.496L421.504 512 195.2 285.696a64 64 0 0 1 0-90.496z" /></svg></a>
|
|
935
|
+
|
|
936
|
+
<a
|
|
937
|
+
tabIndex={-1}
|
|
938
|
+
href="#"
|
|
939
|
+
className="date2d__control-tools__trigger"
|
|
940
|
+
onClick={(e: React.MouseEvent) => {
|
|
941
|
+
e.preventDefault();
|
|
942
|
+
e.stopPropagation(); // Avoid triggering pop-ups
|
|
943
|
+
|
|
944
|
+
handleShow();
|
|
945
|
+
}}
|
|
946
|
+
>
|
|
947
|
+
<svg width="14px" height="14px" viewBox="0 0 24 24" fill="none">
|
|
948
|
+
<path d="M3 9H21M9 15L11 17L15 13M7 3V5M17 3V5M6.2 21H17.8C18.9201 21 19.4802 21 19.908 20.782C20.2843 20.5903 20.5903 20.2843 20.782 19.908C21 19.4802 21 18.9201 21 17.8V8.2C21 7.07989 21 6.51984 20.782 6.09202C20.5903 5.71569 20.2843 5.40973 19.908 5.21799C19.4802 5 18.9201 5 17.8 5H6.2C5.0799 5 4.51984 5 4.09202 5.21799C3.71569 5.40973 3.40973 5.71569 3.21799 6.09202C3 6.51984 3 7.07989 3 8.2V17.8C3 18.9201 3 19.4802 3.21799 19.908C3.40973 20.2843 3.71569 20.5903 4.09202 20.782C4.51984 21 5.07989 21 6.2 21Z" stroke="#000000" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" />
|
|
949
|
+
</svg>
|
|
950
|
+
</a>
|
|
951
|
+
|
|
952
|
+
</span>;
|
|
953
|
+
}
|
|
954
|
+
|
|
905
955
|
|
|
906
956
|
useEffect(() => {
|
|
907
957
|
|
|
@@ -1309,54 +1359,21 @@ const Date = forwardRef((props: DateProps, externalRef: any) => {
|
|
|
1309
1359
|
*/}
|
|
1310
1360
|
|
|
1311
1361
|
</div>
|
|
1362
|
+
|
|
1363
|
+
|
|
1364
|
+
|
|
1365
|
+
{/* TOOLS */}
|
|
1366
|
+
{propExist(iconRight) ? tools() : null}
|
|
1367
|
+
{/* /TOOLS */}
|
|
1368
|
+
|
|
1369
|
+
|
|
1312
1370
|
</>}
|
|
1313
1371
|
style={style}
|
|
1314
1372
|
{...attributes}
|
|
1315
1373
|
/>
|
|
1316
1374
|
|
|
1317
1375
|
{/* TOOLS */}
|
|
1318
|
-
|
|
1319
|
-
'date2d__control-tools',
|
|
1320
|
-
{
|
|
1321
|
-
'date2d__control-tools--hover-show-tools': SHOW_TOOLS_ENABLED
|
|
1322
|
-
}
|
|
1323
|
-
|
|
1324
|
-
)}>
|
|
1325
|
-
|
|
1326
|
-
<a
|
|
1327
|
-
tabIndex={-1}
|
|
1328
|
-
href="#"
|
|
1329
|
-
className={combinedCls(
|
|
1330
|
-
'date2d__control-tools__close',
|
|
1331
|
-
{
|
|
1332
|
-
'd-none': HIDE_CLEAR_BTN_ENABLED || !dateDefaultValueExist
|
|
1333
|
-
}
|
|
1334
|
-
)} onClick={(e: React.MouseEvent) => {
|
|
1335
|
-
e.preventDefault();
|
|
1336
|
-
e.stopPropagation(); // Avoid triggering pop-ups
|
|
1337
|
-
|
|
1338
|
-
clearAll();
|
|
1339
|
-
onClear?.(getFullTimeData(''));
|
|
1340
|
-
}}
|
|
1341
|
-
><svg width="12px" height="12px" viewBox="0 0 1024 1024"><path fill="#000" d="M195.2 195.2a64 64 0 0 1 90.496 0L512 421.504 738.304 195.2a64 64 0 0 1 90.496 90.496L602.496 512 828.8 738.304a64 64 0 0 1-90.496 90.496L512 602.496 285.696 828.8a64 64 0 0 1-90.496-90.496L421.504 512 195.2 285.696a64 64 0 0 1 0-90.496z" /></svg></a>
|
|
1342
|
-
|
|
1343
|
-
<a
|
|
1344
|
-
tabIndex={-1}
|
|
1345
|
-
href="#"
|
|
1346
|
-
className="date2d__control-tools__trigger"
|
|
1347
|
-
onClick={(e: React.MouseEvent) => {
|
|
1348
|
-
e.preventDefault();
|
|
1349
|
-
e.stopPropagation(); // Avoid triggering pop-ups
|
|
1350
|
-
|
|
1351
|
-
handleShow();
|
|
1352
|
-
}}
|
|
1353
|
-
>
|
|
1354
|
-
<svg width="14px" height="14px" viewBox="0 0 24 24" fill="none">
|
|
1355
|
-
<path d="M3 9H21M9 15L11 17L15 13M7 3V5M17 3V5M6.2 21H17.8C18.9201 21 19.4802 21 19.908 20.782C20.2843 20.5903 20.5903 20.2843 20.782 19.908C21 19.4802 21 18.9201 21 17.8V8.2C21 7.07989 21 6.51984 20.782 6.09202C20.5903 5.71569 20.2843 5.40973 19.908 5.21799C19.4802 5 18.9201 5 17.8 5H6.2C5.0799 5 4.51984 5 4.09202 5.21799C3.71569 5.40973 3.40973 5.71569 3.21799 6.09202C3 6.51984 3 7.07989 3 8.2V17.8C3 18.9201 3 19.4802 3.21799 19.908C3.40973 20.2843 3.71569 20.5903 4.09202 20.782C4.51984 21 5.07989 21 6.2 21Z" stroke="#000000" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" />
|
|
1356
|
-
</svg>
|
|
1357
|
-
</a>
|
|
1358
|
-
|
|
1359
|
-
</span>
|
|
1376
|
+
{!propExist(iconRight) ? tools() : null}
|
|
1360
1377
|
{/* /TOOLS */}
|
|
1361
1378
|
|
|
1362
1379
|
|
package/lib/esm/Input/index.tsx
CHANGED
|
@@ -6,6 +6,7 @@ import { clsWrite, combinedCls } from 'funda-utils/dist/cjs/cls';
|
|
|
6
6
|
import { actualPropertyValue, getTextTop } from 'funda-utils/dist/cjs/inputsCalculation';
|
|
7
7
|
import useDebounce from 'funda-utils/dist/cjs/useDebounce';
|
|
8
8
|
|
|
9
|
+
|
|
9
10
|
export type InputProps = {
|
|
10
11
|
contentRef?: React.ForwardedRef<any>;
|
|
11
12
|
wrapperClassName?: string;
|
package/lib/esm/Select/index.tsx
CHANGED
|
@@ -50,7 +50,6 @@ import { clsWrite, combinedCls } from 'funda-utils/dist/cjs/cls';
|
|
|
50
50
|
|
|
51
51
|
|
|
52
52
|
|
|
53
|
-
|
|
54
53
|
export type SelectOptionChangeFnType = (arg1: any, arg2: any, arg3: any) => void;
|
|
55
54
|
|
|
56
55
|
export interface MultiSelectDataConfig {
|
|
@@ -68,9 +67,9 @@ export interface OptionConfig {
|
|
|
68
67
|
disabled?: boolean;
|
|
69
68
|
optgroup?: any[];
|
|
70
69
|
group?: boolean;
|
|
71
|
-
label:
|
|
72
|
-
listItemLabel?:
|
|
73
|
-
value:
|
|
70
|
+
label: string;
|
|
71
|
+
listItemLabel?: string;
|
|
72
|
+
value: string | number | boolean;
|
|
74
73
|
queryString: string | number;
|
|
75
74
|
callback?: () => void;
|
|
76
75
|
}
|
|
@@ -109,7 +108,7 @@ export type SelectProps = {
|
|
|
109
108
|
multiSelect?: MultiSelectConfig;
|
|
110
109
|
multiSelectEntireAreaTrigger?: boolean;
|
|
111
110
|
multiSelectSelectedItemOnlyStatus?: multiSelectSelectedItemOnlyStatusConfig;
|
|
112
|
-
renderSelectedValue?: (selectedData: MultiSelectControlValConfig, removeFunc: (e: React.MouseEvent) => void) =>
|
|
111
|
+
renderSelectedValue?: (selectedData: MultiSelectControlValConfig, removeFunc: (e: React.MouseEvent) => void) => React.ReactNode;
|
|
113
112
|
cleanTrigger?: CleanTriggerConfig;
|
|
114
113
|
defaultValue?: string | OptionConfig;
|
|
115
114
|
value?: string | OptionConfig;
|
|
@@ -13,6 +13,12 @@ import { clsWrite, combinedCls } from 'funda-utils/dist/cjs/cls';
|
|
|
13
13
|
|
|
14
14
|
|
|
15
15
|
|
|
16
|
+
export interface TagValConfig {
|
|
17
|
+
content: string;
|
|
18
|
+
id: number;
|
|
19
|
+
[key: string]: string | boolean | number; // Allows dynamic attributes
|
|
20
|
+
}
|
|
21
|
+
|
|
16
22
|
export type TagInputProps = {
|
|
17
23
|
contentRef?: React.ForwardedRef<any>;
|
|
18
24
|
wrapperClassName?: string;
|
|
@@ -27,6 +33,7 @@ export type TagInputProps = {
|
|
|
27
33
|
required?: any;
|
|
28
34
|
readOnly?: any;
|
|
29
35
|
placeholder?: string;
|
|
36
|
+
renderSelectedValue?: (selectedData: TagValConfig[], removeFunc: (e: React.MouseEvent) => void) => React.ReactNode;
|
|
30
37
|
/** Whether to use square brackets to save result and initialize default value */
|
|
31
38
|
extractValueByBrackets?: boolean;
|
|
32
39
|
/** -- */
|
|
@@ -52,6 +59,7 @@ const TagInput = forwardRef((props: TagInputProps, externalRef: any) => {
|
|
|
52
59
|
disabled,
|
|
53
60
|
required,
|
|
54
61
|
placeholder,
|
|
62
|
+
renderSelectedValue,
|
|
55
63
|
readOnly,
|
|
56
64
|
value,
|
|
57
65
|
requiredLabel,
|
|
@@ -82,7 +90,7 @@ const TagInput = forwardRef((props: TagInputProps, externalRef: any) => {
|
|
|
82
90
|
const max = maxTags ? maxTags : 10;
|
|
83
91
|
const [lastId, setLastId] = useState<number>(-1);
|
|
84
92
|
const [userInput, setUserInput] = useState<string>('');
|
|
85
|
-
const [items, setItems] = useState<
|
|
93
|
+
const [items, setItems] = useState<TagValConfig[]>([]);
|
|
86
94
|
const [alreadyInItems, setAlreadyInItems] = useState<boolean>(false);
|
|
87
95
|
const [onComposition, setOnComposition] = useState<boolean>(false);
|
|
88
96
|
|
|
@@ -115,7 +123,7 @@ const TagInput = forwardRef((props: TagInputProps, externalRef: any) => {
|
|
|
115
123
|
} else {
|
|
116
124
|
const _val = VALUE_BY_BRACKETS ? extractContentsOfBrackets(defaultValue) : defaultValue.trim().replace(/^\,|\,$/g, '').split(',');
|
|
117
125
|
if (Array.isArray(_val)) {
|
|
118
|
-
setItems(_val.map((item:
|
|
126
|
+
setItems(_val.map((item: string, index: number) => {
|
|
119
127
|
return {
|
|
120
128
|
content: item,
|
|
121
129
|
id: index
|
|
@@ -129,13 +137,15 @@ const TagInput = forwardRef((props: TagInputProps, externalRef: any) => {
|
|
|
129
137
|
}
|
|
130
138
|
|
|
131
139
|
|
|
132
|
-
function handleRemove(e:
|
|
140
|
+
function handleRemove(e: any) {
|
|
133
141
|
e.preventDefault();
|
|
142
|
+
e.stopPropagation(); /* REQUIRED */
|
|
134
143
|
|
|
135
144
|
const idToRemove = Number(e.currentTarget.dataset.item);
|
|
136
145
|
const newArray = items!.filter((item: any) => item.id !== idToRemove);
|
|
137
146
|
setItems(newArray);
|
|
138
147
|
|
|
148
|
+
|
|
139
149
|
//
|
|
140
150
|
onChange?.(inputRef.current, newArray, VALUE_BY_BRACKETS ? convertArrToValByBrackets(newArray.map(v => v.content)) : newArray.map(v => v.content).join(','));
|
|
141
151
|
}
|
|
@@ -270,13 +280,23 @@ const TagInput = forwardRef((props: TagInputProps, externalRef: any) => {
|
|
|
270
280
|
<div className="tag-input__control-wrapper">
|
|
271
281
|
<div>
|
|
272
282
|
<ul className="tag-input__list">
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
283
|
+
|
|
284
|
+
{/* ITEMS LIST */}
|
|
285
|
+
{typeof renderSelectedValue === 'function' ? <>
|
|
286
|
+
{renderSelectedValue(items, handleRemove)}
|
|
287
|
+
</> : <>
|
|
288
|
+
{items ? items.map((item: any, index: number) => (
|
|
289
|
+
<li key={index}>
|
|
290
|
+
{item.content}
|
|
291
|
+
|
|
292
|
+
<a href="#" tabIndex={-1} onClick={handleRemove} data-item={item.id}><svg width="10px" height="10px" viewBox="0 0 1024 1024"><path fill="#000" d="M195.2 195.2a64 64 0 0 1 90.496 0L512 421.504 738.304 195.2a64 64 0 0 1 90.496 90.496L602.496 512 828.8 738.304a64 64 0 0 1-90.496 90.496L512 602.496 285.696 828.8a64 64 0 0 1-90.496-90.496L421.504 512 195.2 285.696a64 64 0 0 1 0-90.496z"/></svg></a>
|
|
293
|
+
</li>
|
|
294
|
+
)) : null}
|
|
295
|
+
</>}
|
|
296
|
+
|
|
297
|
+
|
|
298
|
+
|
|
299
|
+
|
|
280
300
|
</ul>
|
|
281
301
|
|
|
282
302
|
|
|
@@ -8,6 +8,7 @@ import { actualPropertyValue, getTextTop } from 'funda-utils/dist/cjs/inputsCalc
|
|
|
8
8
|
import useDebounce from 'funda-utils/dist/cjs/useDebounce';
|
|
9
9
|
|
|
10
10
|
|
|
11
|
+
|
|
11
12
|
export type TextareaProps = {
|
|
12
13
|
contentRef?: React.ForwardedRef<any>; // could use "Array" on contentRef.current, such as contentRef.current[0], contentRef.current[1]
|
|
13
14
|
wrapperClassName?: string;
|
|
@@ -51,7 +51,6 @@ const App = () => {
|
|
|
51
51
|
|
|
52
52
|
*/
|
|
53
53
|
import { useEffect, useState, useCallback } from "react";
|
|
54
|
-
|
|
55
54
|
export interface AutosizeTextAreaProps {
|
|
56
55
|
el: any;
|
|
57
56
|
value: string;
|
|
@@ -66,68 +65,67 @@ const useAutosizeTextArea = ({
|
|
|
66
65
|
cb
|
|
67
66
|
}: AutosizeTextAreaProps): { reset: () => void } => {
|
|
68
67
|
|
|
69
|
-
const [defaultRowHeight, setDefaultRowHeight] = useState(0);
|
|
70
68
|
const [defaultRowHeightInit, setDefaultRowHeightInit] = useState(false);
|
|
71
69
|
|
|
72
70
|
// Reset function to restore default height
|
|
73
71
|
const reset = useCallback(() => {
|
|
74
|
-
if (el
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
72
|
+
if (!el) return;
|
|
73
|
+
|
|
74
|
+
const scrollHeight = el.scrollHeight;
|
|
75
|
+
el.style.height = scrollHeight + "px";
|
|
76
|
+
|
|
77
|
+
// Get current dimensions after reset
|
|
78
|
+
const style = window.getComputedStyle(el);
|
|
79
|
+
const _controlWidth = el.scrollWidth + parseInt(style.borderLeftWidth) + parseInt(style.borderRightWidth);
|
|
80
|
+
cb?.([_controlWidth, scrollHeight]);
|
|
81
|
+
}, [el, cb]);
|
|
83
82
|
|
|
84
83
|
useEffect(() => {
|
|
85
|
-
if (el)
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
setDefaultRowHeightInit(true);
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
// restore default row height
|
|
102
|
-
if (defaultRowHeight > 0) {
|
|
103
|
-
el.style.height = defaultRowHeight + "px";
|
|
84
|
+
if (!el) return;
|
|
85
|
+
|
|
86
|
+
// Initialize default height
|
|
87
|
+
if (!defaultRowHeightInit) {
|
|
88
|
+
el.style.height = 'auto';
|
|
89
|
+
const initialHeight = el.scrollHeight;
|
|
90
|
+
setDefaultRowHeightInit(true);
|
|
91
|
+
|
|
92
|
+
// If the height is 0, set it to "auto"
|
|
93
|
+
if (initialHeight === 0) {
|
|
94
|
+
el.style.height = "auto";
|
|
95
|
+
} else {
|
|
96
|
+
el.style.height = initialHeight + "px";
|
|
104
97
|
}
|
|
105
98
|
|
|
106
|
-
|
|
107
|
-
const scrollHeight = el.scrollHeight;
|
|
99
|
+
}
|
|
108
100
|
|
|
101
|
+
// Get dimensions
|
|
102
|
+
const style = window.getComputedStyle(el);
|
|
103
|
+
const _controlWidth = el.scrollWidth + parseInt(style.borderLeftWidth) + parseInt(style.borderRightWidth);
|
|
104
|
+
|
|
105
|
+
// Calculate height
|
|
106
|
+
el.style.height = 'auto';
|
|
107
|
+
let finalHeight = el.scrollHeight;
|
|
108
|
+
|
|
109
|
+
// Apply max height limit if needed
|
|
110
|
+
if (maxHeight > 0 && finalHeight > maxHeight) {
|
|
111
|
+
finalHeight = maxHeight;
|
|
112
|
+
}
|
|
109
113
|
|
|
110
|
-
|
|
111
|
-
|
|
114
|
+
// Set final height
|
|
115
|
+
// If the height is 0, set it to "auto"
|
|
116
|
+
if (finalHeight === 0) {
|
|
117
|
+
el.style.height = "auto";
|
|
118
|
+
} else {
|
|
119
|
+
el.style.height = finalHeight + "px";
|
|
120
|
+
}
|
|
112
121
|
|
|
113
|
-
// !!! Compare initial height and changed height
|
|
114
|
-
if (scrollHeight > defaultRowHeight && defaultRowHeight > 0) {
|
|
115
122
|
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
_scrollHeight = maxHeight;
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
el.style.height = _scrollHeight + "px";
|
|
122
|
-
|
|
123
|
-
}
|
|
123
|
+
// Callback
|
|
124
|
+
cb?.([_controlWidth, finalHeight]);
|
|
124
125
|
|
|
125
|
-
|
|
126
|
-
}
|
|
127
|
-
}, [el, value]);
|
|
126
|
+
}, [el, value, maxHeight, defaultRowHeightInit]);
|
|
128
127
|
|
|
129
128
|
return { reset };
|
|
130
129
|
};
|
|
131
130
|
|
|
132
|
-
export default useAutosizeTextArea;
|
|
133
|
-
|
|
131
|
+
export default useAutosizeTextArea;
|