funda-ui 4.4.15 → 4.5.12
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/Date/index.js +1078 -77
- package/EventCalendar/index.css +114 -114
- package/EventCalendar/index.d.ts +1 -0
- package/EventCalendar/index.js +124 -86
- package/EventCalendarTimeline/index.css +274 -270
- package/EventCalendarTimeline/index.d.ts +3 -0
- package/EventCalendarTimeline/index.js +673 -225
- package/Input/index.d.ts +7 -0
- package/Input/index.js +699 -57
- package/MasonryLayout/index.js +11 -1
- package/MultipleCheckboxes/index.js +11 -11
- package/MultipleSelect/index.d.ts +1 -0
- package/MultipleSelect/index.js +18 -16
- package/NativeSelect/index.js +11 -11
- package/Radio/index.js +11 -11
- package/RangeSlider/index.js +1078 -77
- package/Select/index.js +45 -13
- package/Table/index.css +1 -0
- package/Table/index.js +36 -7
- package/TagInput/index.d.ts +1 -0
- package/TagInput/index.js +20 -2
- package/Textarea/index.d.ts +7 -0
- package/Textarea/index.js +707 -10
- package/Tree/index.js +13 -11
- package/Utils/inputsCalculation.d.ts +18 -1
- package/Utils/inputsCalculation.js +26 -0
- package/Utils/object.js +11 -11
- package/Utils/os.d.ts +2 -0
- package/Utils/os.js +104 -0
- package/lib/cjs/Date/index.js +1078 -77
- package/lib/cjs/EventCalendar/index.d.ts +1 -0
- package/lib/cjs/EventCalendar/index.js +124 -86
- package/lib/cjs/EventCalendarTimeline/index.d.ts +3 -0
- package/lib/cjs/EventCalendarTimeline/index.js +673 -225
- package/lib/cjs/Input/index.d.ts +7 -0
- package/lib/cjs/Input/index.js +699 -57
- package/lib/cjs/MasonryLayout/index.js +11 -1
- package/lib/cjs/MultipleCheckboxes/index.js +11 -11
- package/lib/cjs/MultipleSelect/index.d.ts +1 -0
- package/lib/cjs/MultipleSelect/index.js +18 -16
- package/lib/cjs/NativeSelect/index.js +11 -11
- package/lib/cjs/Radio/index.js +11 -11
- package/lib/cjs/RangeSlider/index.js +1078 -77
- package/lib/cjs/Select/index.js +45 -13
- package/lib/cjs/Table/index.js +36 -7
- package/lib/cjs/TagInput/index.d.ts +1 -0
- package/lib/cjs/TagInput/index.js +20 -2
- package/lib/cjs/Textarea/index.d.ts +7 -0
- package/lib/cjs/Textarea/index.js +707 -10
- package/lib/cjs/Tree/index.js +13 -11
- package/lib/cjs/Utils/inputsCalculation.d.ts +18 -1
- package/lib/cjs/Utils/inputsCalculation.js +26 -0
- package/lib/cjs/Utils/object.js +11 -11
- package/lib/cjs/Utils/os.d.ts +2 -0
- package/lib/cjs/Utils/os.js +104 -0
- package/lib/css/EventCalendar/index.css +114 -114
- package/lib/css/EventCalendarTimeline/index.css +274 -270
- package/lib/css/Table/index.css +1 -0
- package/lib/esm/EventCalendar/index.scss +81 -81
- package/lib/esm/EventCalendar/index.tsx +144 -104
- package/lib/esm/EventCalendarTimeline/index.scss +226 -221
- package/lib/esm/EventCalendarTimeline/index.tsx +791 -517
- package/lib/esm/Input/index.tsx +299 -77
- package/lib/esm/MasonryLayout/index.tsx +9 -2
- package/lib/esm/ModalDialog/index.tsx +0 -1
- package/lib/esm/MultipleSelect/index.tsx +6 -4
- package/lib/esm/Table/Table.tsx +0 -1
- package/lib/esm/Table/index.scss +2 -0
- package/lib/esm/Table/utils/hooks/useTableDraggable.tsx +47 -6
- package/lib/esm/TagInput/index.tsx +23 -1
- package/lib/esm/Textarea/index.tsx +332 -39
- package/lib/esm/Tree/TreeList.tsx +4 -1
- package/lib/esm/Tree/index.tsx +1 -0
- package/lib/esm/Utils/libs/inputsCalculation.ts +60 -31
- package/lib/esm/Utils/libs/object.ts +67 -67
- package/lib/esm/Utils/libs/os.ts +63 -0
- package/package.json +1 -1
package/lib/esm/Input/index.tsx
CHANGED
|
@@ -3,6 +3,9 @@ import React, { useState, useEffect, useRef, forwardRef, ChangeEvent, Compositio
|
|
|
3
3
|
|
|
4
4
|
import useComId from 'funda-utils/dist/cjs/useComId';
|
|
5
5
|
import { clsWrite, combinedCls } from 'funda-utils/dist/cjs/cls';
|
|
6
|
+
import { actualPropertyValue, getTextTop } from 'funda-utils/dist/cjs/inputsCalculation';
|
|
7
|
+
import useDebounce from 'funda-utils/dist/cjs/useDebounce';
|
|
8
|
+
|
|
6
9
|
|
|
7
10
|
|
|
8
11
|
export type InputProps = {
|
|
@@ -20,8 +23,8 @@ export type InputProps = {
|
|
|
20
23
|
units?: React.ReactNode | string;
|
|
21
24
|
name?: string;
|
|
22
25
|
step?: any;
|
|
23
|
-
|
|
24
|
-
|
|
26
|
+
min?: any;
|
|
27
|
+
max?: any;
|
|
25
28
|
src?: any;
|
|
26
29
|
size?: any;
|
|
27
30
|
minLength?: any;
|
|
@@ -36,6 +39,13 @@ export type InputProps = {
|
|
|
36
39
|
iconLeft?: React.ReactNode | string;
|
|
37
40
|
iconRight?: React.ReactNode | string;
|
|
38
41
|
appendControl?: React.ReactNode;
|
|
42
|
+
aiPredict?: boolean;
|
|
43
|
+
aiPredictRemainingTextRGB?: number[];
|
|
44
|
+
aiPredictConfirmKey?: Array<string[]>;
|
|
45
|
+
aiPredictFetchFuncAsync?: any;
|
|
46
|
+
aiPredictFetchFuncMethod?: string;
|
|
47
|
+
aiPredictFetchFuncMethodParams?: any[];
|
|
48
|
+
aiPredictFetchCallback?: (data: any) => void;
|
|
39
49
|
/** -- */
|
|
40
50
|
id?: string;
|
|
41
51
|
style?: React.CSSProperties;
|
|
@@ -86,6 +96,13 @@ const Input = forwardRef((props: InputProps, externalRef: any) => {
|
|
|
86
96
|
inputMode,
|
|
87
97
|
id,
|
|
88
98
|
appendControl,
|
|
99
|
+
aiPredict = false,
|
|
100
|
+
aiPredictRemainingTextRGB = [153, 153, 153],
|
|
101
|
+
aiPredictConfirmKey = [['Enter'], ['Tab'], ['Shift', ' ']],
|
|
102
|
+
aiPredictFetchFuncAsync,
|
|
103
|
+
aiPredictFetchFuncMethod,
|
|
104
|
+
aiPredictFetchFuncMethodParams,
|
|
105
|
+
aiPredictFetchCallback,
|
|
89
106
|
iconLeft,
|
|
90
107
|
iconRight,
|
|
91
108
|
autoComplete,
|
|
@@ -112,8 +129,175 @@ const Input = forwardRef((props: InputProps, externalRef: any) => {
|
|
|
112
129
|
const [onComposition, setOnComposition] = useState<boolean>(false);
|
|
113
130
|
const [changedVal, setChangedVal] = useState<string>(value || '');
|
|
114
131
|
|
|
132
|
+
|
|
133
|
+
//================================================================
|
|
134
|
+
// AI Predict
|
|
135
|
+
//================================================================
|
|
136
|
+
const [currentSuggestion, setCurrentSuggestion] = useState<string>('');
|
|
137
|
+
const [tempMatchedSuggestion, setTempMatchedSuggestion] = useState<string[]>([]);
|
|
138
|
+
const [textWidth, setTextWidth] = useState<number>(0);
|
|
139
|
+
const aiInputRef = useRef<any>(null);
|
|
140
|
+
const originInputComputedStyle = useRef<Record<string, any>>({
|
|
141
|
+
fontSize: 16,
|
|
142
|
+
fontFamily: 'inherit',
|
|
143
|
+
letterSpacing: 'normal',
|
|
144
|
+
textTop: 10
|
|
145
|
+
});
|
|
146
|
+
const [hasErr, setHasErr] = useState<boolean>(false);
|
|
147
|
+
const currentSuggestionIndex = useRef<number>(0);
|
|
148
|
+
|
|
115
149
|
|
|
116
150
|
|
|
151
|
+
|
|
152
|
+
// A list of suggestions
|
|
153
|
+
//----------------
|
|
154
|
+
const [suggestions, setSuggestions] = useState<string[]>([]);
|
|
155
|
+
|
|
156
|
+
//performance
|
|
157
|
+
const handleChangeSuggestionsFetchSafe = useDebounce((e: any, curVal: string) => {
|
|
158
|
+
const _oparams: any[] = aiPredictFetchFuncMethodParams || [];
|
|
159
|
+
const _params: any[] = _oparams.map((item: any) => item !== '$QUERY_STRING' ? item : curVal);
|
|
160
|
+
fetchSuggestionsData((_params).join(',')).then((resSuggestions: string[]) => {
|
|
161
|
+
handleInputAiPredictChange(curVal, resSuggestions);
|
|
162
|
+
});
|
|
163
|
+
}, 350, []);
|
|
164
|
+
|
|
165
|
+
async function fetchSuggestionsData(params: any) {
|
|
166
|
+
|
|
167
|
+
if (typeof aiPredictFetchFuncAsync === 'object') {
|
|
168
|
+
|
|
169
|
+
const response: any = await aiPredictFetchFuncAsync[`${aiPredictFetchFuncMethod}`](...params.split(','));
|
|
170
|
+
let _ORGIN_DATA = response.data;
|
|
171
|
+
|
|
172
|
+
// reset data structure
|
|
173
|
+
if (typeof (aiPredictFetchCallback) === 'function') {
|
|
174
|
+
_ORGIN_DATA = aiPredictFetchCallback(_ORGIN_DATA);
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
// Determine whether the data structure matches
|
|
178
|
+
if (!Array.isArray(_ORGIN_DATA)) {
|
|
179
|
+
console.warn('The data structure does not match, please refer to the example in the component documentation.');
|
|
180
|
+
setHasErr(true);
|
|
181
|
+
_ORGIN_DATA = [];
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
|
|
185
|
+
//
|
|
186
|
+
setSuggestions(_ORGIN_DATA);
|
|
187
|
+
|
|
188
|
+
return _ORGIN_DATA;
|
|
189
|
+
} else {
|
|
190
|
+
return [];
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
|
|
197
|
+
|
|
198
|
+
// Calculates the width of the input text
|
|
199
|
+
//----------------
|
|
200
|
+
const calculateTextWidth = (text: string) => {
|
|
201
|
+
if (valRef.current) {
|
|
202
|
+
const canvas = document.createElement('canvas');
|
|
203
|
+
const context: any = canvas.getContext('2d');
|
|
204
|
+
context.font = `${originInputComputedStyle.current.fontSize}px ${originInputComputedStyle.current.fontFamily}`;
|
|
205
|
+
return context.measureText(text).width;
|
|
206
|
+
}
|
|
207
|
+
return 0;
|
|
208
|
+
};
|
|
209
|
+
|
|
210
|
+
|
|
211
|
+
// Get the rest of the suggested text
|
|
212
|
+
//----------------
|
|
213
|
+
const getRemainingText = (fullSuggestion: string) => {
|
|
214
|
+
if (!changedVal || !fullSuggestion) return '';
|
|
215
|
+
|
|
216
|
+
|
|
217
|
+
// Only the parts of the suggested text that were not entered are returned
|
|
218
|
+
const lastInputChar = changedVal[changedVal.length - 1];
|
|
219
|
+
const lastCharIndex = fullSuggestion.toLowerCase().lastIndexOf(lastInputChar.toLowerCase());
|
|
220
|
+
return fullSuggestion.slice(lastCharIndex + 1);
|
|
221
|
+
|
|
222
|
+
};
|
|
223
|
+
|
|
224
|
+
// Match exactly from the start
|
|
225
|
+
//----------------
|
|
226
|
+
const preciseMatch = (input: any, suggestions: string[]) => {
|
|
227
|
+
if (!input) return '';
|
|
228
|
+
|
|
229
|
+
const filtered = suggestions.filter(s =>
|
|
230
|
+
s.toLowerCase().startsWith(input.toLowerCase())
|
|
231
|
+
);
|
|
232
|
+
|
|
233
|
+
setTempMatchedSuggestion(filtered);
|
|
234
|
+
return filtered;
|
|
235
|
+
};
|
|
236
|
+
|
|
237
|
+
|
|
238
|
+
// Fuzzy matching
|
|
239
|
+
//----------------
|
|
240
|
+
const fuzzyMatch = (input: any, suggestions: string[]) => {
|
|
241
|
+
if (!input) return '';
|
|
242
|
+
|
|
243
|
+
// Convert input to a regular expression pattern with support for arbitrary position matching
|
|
244
|
+
const pattern = input.split('').map((char: string) =>
|
|
245
|
+
char.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')
|
|
246
|
+
).join('.*');
|
|
247
|
+
const regex = new RegExp(pattern, 'i');
|
|
248
|
+
|
|
249
|
+
// Find the first matching suggestion (multiple matches)
|
|
250
|
+
const filtered = suggestions.filter((suggestion: string) => regex.test(suggestion));
|
|
251
|
+
setTempMatchedSuggestion(filtered);
|
|
252
|
+
return filtered;
|
|
253
|
+
};
|
|
254
|
+
|
|
255
|
+
// Handle input variations
|
|
256
|
+
//----------------
|
|
257
|
+
const handleInputAiPredictChange = (newValue: string, curSuggestions: string[]) => {
|
|
258
|
+
setTextWidth(calculateTextWidth(newValue));
|
|
259
|
+
|
|
260
|
+
// Match results
|
|
261
|
+
const matchedSuggestion = fuzzyMatch(newValue, curSuggestions);
|
|
262
|
+
setCurrentSuggestion(matchedSuggestion[0] || '');
|
|
263
|
+
|
|
264
|
+
};
|
|
265
|
+
|
|
266
|
+
|
|
267
|
+
|
|
268
|
+
|
|
269
|
+
// Calculate the color shade of the prompt text
|
|
270
|
+
//----------------
|
|
271
|
+
const calculateOpacity = () => {
|
|
272
|
+
// Transparency is calculated based on the input length
|
|
273
|
+
const baseOpacity = 0.5;
|
|
274
|
+
const inputLength = changedVal.length;
|
|
275
|
+
return Math.max(0.2, baseOpacity - (inputLength * 0.05));
|
|
276
|
+
};
|
|
277
|
+
|
|
278
|
+
|
|
279
|
+
|
|
280
|
+
// Confirm
|
|
281
|
+
//----------------
|
|
282
|
+
const handleAiPredictKeyDown = (e: KeyboardEvent<HTMLInputElement>) => {
|
|
283
|
+
// Prevents the default behavior of the enter key
|
|
284
|
+
e.preventDefault();
|
|
285
|
+
|
|
286
|
+
const remainingText = getRemainingText(currentSuggestion);
|
|
287
|
+
if (remainingText) {
|
|
288
|
+
// Only the second half of the text is added
|
|
289
|
+
setChangedVal(changedVal + remainingText);
|
|
290
|
+
setCurrentSuggestion('');
|
|
291
|
+
}
|
|
292
|
+
};
|
|
293
|
+
|
|
294
|
+
//
|
|
295
|
+
const remainingText = getRemainingText(currentSuggestion);
|
|
296
|
+
|
|
297
|
+
|
|
298
|
+
//================================================================
|
|
299
|
+
// General
|
|
300
|
+
//================================================================
|
|
117
301
|
// exposes the following methods
|
|
118
302
|
useImperativeHandle(
|
|
119
303
|
contentRef,
|
|
@@ -151,7 +335,7 @@ const Input = forwardRef((props: InputProps, externalRef: any) => {
|
|
|
151
335
|
rootRef.current?.classList.add('focus');
|
|
152
336
|
|
|
153
337
|
//
|
|
154
|
-
onFocus?.(event, onComposition, valRef.current);
|
|
338
|
+
onFocus?.(event, onComposition, valRef.current);
|
|
155
339
|
}
|
|
156
340
|
|
|
157
341
|
function handleChange(event: ChangeEvent<HTMLInputElement>) {
|
|
@@ -159,7 +343,7 @@ const Input = forwardRef((props: InputProps, externalRef: any) => {
|
|
|
159
343
|
|
|
160
344
|
setChangedVal(val);
|
|
161
345
|
|
|
162
|
-
|
|
346
|
+
|
|
163
347
|
//----
|
|
164
348
|
//remove focus style
|
|
165
349
|
if (val === '') {
|
|
@@ -198,28 +382,75 @@ const Input = forwardRef((props: InputProps, externalRef: any) => {
|
|
|
198
382
|
if (newData) setChangedVal(newData); // Avoid the error "react checkbox changing an uncontrolled input to be controlled"
|
|
199
383
|
}
|
|
200
384
|
}
|
|
201
|
-
|
|
385
|
+
|
|
386
|
+
|
|
202
387
|
function handleKeyPressed(event: KeyboardEvent<HTMLInputElement>) {
|
|
203
388
|
if (typeof (onKeyPressedCallback) === 'function') {
|
|
204
389
|
const newData: any = onKeyPressedCallback(event, valRef.current);
|
|
205
390
|
if (newData) setChangedVal(newData); // Avoid the error "react checkbox changing an uncontrolled input to be controlled"
|
|
206
391
|
}
|
|
207
392
|
|
|
393
|
+
|
|
208
394
|
if (event.code == "Enter") {
|
|
209
395
|
// DO NOT USE "preventDefault()"
|
|
210
396
|
onPressEnter?.(event, valRef.current);
|
|
211
397
|
}
|
|
212
398
|
|
|
399
|
+
|
|
400
|
+
// AI Predict
|
|
401
|
+
//----
|
|
402
|
+
if (aiPredict && currentSuggestion !== '') {
|
|
403
|
+
const keyBindings: Array<string[]> = aiPredictConfirmKey;
|
|
404
|
+
// The parameter 'registerKeyEvents' is an array, and each element is an object
|
|
405
|
+
// eg. { keys: ["Control", "S"], action: () => { console.log("Ctrl+S"); } }
|
|
406
|
+
const registerKeyEvents: Record<string, any>[] = keyBindings.map((s: string[]) => {
|
|
407
|
+
return {
|
|
408
|
+
keys: s,
|
|
409
|
+
action: () => {
|
|
410
|
+
handleAiPredictKeyDown(event);
|
|
411
|
+
},
|
|
412
|
+
};
|
|
413
|
+
});
|
|
414
|
+
|
|
415
|
+
registerKeyEvents.forEach((binding: Record<string, any>) => {
|
|
416
|
+
const keysPressed = binding.keys.every((key: string) =>
|
|
417
|
+
key === "Shift" ? event.shiftKey :
|
|
418
|
+
key === "Control" ? event.ctrlKey :
|
|
419
|
+
key === "Alt" ? event.altKey :
|
|
420
|
+
key === "Meta" ? event.metaKey :
|
|
421
|
+
event.key === key
|
|
422
|
+
);
|
|
423
|
+
|
|
424
|
+
if (keysPressed) {
|
|
425
|
+
binding.action();
|
|
426
|
+
}
|
|
427
|
+
});
|
|
428
|
+
|
|
429
|
+
|
|
430
|
+
// switch result of suggestions
|
|
431
|
+
if (event.code === 'ArrowUp') {
|
|
432
|
+
currentSuggestionIndex.current = (currentSuggestionIndex.current - 1 + tempMatchedSuggestion.length) % tempMatchedSuggestion.length;
|
|
433
|
+
}
|
|
434
|
+
|
|
435
|
+
if (event.code === 'ArrowDown') {
|
|
436
|
+
currentSuggestionIndex.current = (currentSuggestionIndex.current + 1) % tempMatchedSuggestion.length;
|
|
437
|
+
}
|
|
438
|
+
setCurrentSuggestion(tempMatchedSuggestion[currentSuggestionIndex.current] || '');
|
|
439
|
+
|
|
440
|
+
}
|
|
441
|
+
|
|
442
|
+
|
|
213
443
|
}
|
|
214
444
|
|
|
445
|
+
|
|
215
446
|
useEffect(() => {
|
|
216
|
-
|
|
447
|
+
|
|
217
448
|
// update default value
|
|
218
449
|
//--------------
|
|
219
450
|
if (typeof value !== 'undefined') {
|
|
220
451
|
setChangedVal(`${value}`); // Avoid displaying the number 0
|
|
221
452
|
}
|
|
222
|
-
|
|
453
|
+
|
|
223
454
|
|
|
224
455
|
}, [value]);
|
|
225
456
|
|
|
@@ -232,6 +463,19 @@ const Input = forwardRef((props: InputProps, externalRef: any) => {
|
|
|
232
463
|
setChangedVal(`${defaultValue}`); // Avoid displaying the number 0
|
|
233
464
|
}
|
|
234
465
|
|
|
466
|
+
|
|
467
|
+
// AI Predict initalization
|
|
468
|
+
//--------------
|
|
469
|
+
if (aiPredict && valRef.current !== null) {
|
|
470
|
+
originInputComputedStyle.current = {
|
|
471
|
+
fontSize: actualPropertyValue(valRef.current as HTMLInputElement, 'fontSize'),
|
|
472
|
+
fontFamily: actualPropertyValue(valRef.current as HTMLInputElement, 'fontFamily'),
|
|
473
|
+
letterSpacing: actualPropertyValue(valRef.current as HTMLInputElement, 'letterSpacing'),
|
|
474
|
+
textTop: getTextTop(valRef.current)
|
|
475
|
+
};
|
|
476
|
+
}
|
|
477
|
+
|
|
478
|
+
|
|
235
479
|
}, []);
|
|
236
480
|
|
|
237
481
|
|
|
@@ -239,76 +483,19 @@ const Input = forwardRef((props: InputProps, externalRef: any) => {
|
|
|
239
483
|
<>
|
|
240
484
|
|
|
241
485
|
<div className={clsWrite(wrapperClassName, 'mb-3 position-relative')} ref={rootRef}>
|
|
242
|
-
{label ? <>{typeof label === 'string' ? <label htmlFor={idRes} className="form-label" dangerouslySetInnerHTML={{__html: `${label}`}}></label> : <label htmlFor={idRes} className="form-label">{label}</label>}</> : null}
|
|
243
|
-
|
|
486
|
+
{label ? <>{typeof label === 'string' ? <label htmlFor={idRes} className="form-label" dangerouslySetInnerHTML={{ __html: `${label}` }}></label> : <label htmlFor={idRes} className="form-label">{label}</label>}</> : null}
|
|
487
|
+
|
|
244
488
|
<div className={combinedCls(
|
|
245
|
-
'position-relative',
|
|
489
|
+
'position-relative z-1',
|
|
246
490
|
clsWrite(controlGroupWrapperClassName, 'input-group'),
|
|
247
491
|
{
|
|
248
492
|
'has-left-content': propExist(iconLeft),
|
|
249
493
|
'has-right-content': propExist(iconRight) || propExist(units)
|
|
250
494
|
}
|
|
251
495
|
)}>
|
|
252
|
-
{propExist(iconLeft) ? <><span className={clsWrite(controlGroupTextClassName, 'input-group-text')}>{iconLeft}</span
|
|
253
|
-
|
|
254
|
-
{appendControl && (propExist(iconLeft)) ? <>
|
|
255
|
-
<div className="input-group-control-container w-100 position-relative">
|
|
256
|
-
|
|
257
|
-
<input
|
|
258
|
-
ref={(node) => {
|
|
259
|
-
valRef.current = node;
|
|
260
|
-
if (typeof externalRef === 'function') {
|
|
261
|
-
externalRef(node);
|
|
262
|
-
} else if (externalRef) {
|
|
263
|
-
externalRef.current = node;
|
|
264
|
-
}
|
|
265
|
-
}}
|
|
266
|
-
|
|
267
|
-
tabIndex={tabIndex || 0}
|
|
268
|
-
type={typeRes}
|
|
269
|
-
className={combinedCls(
|
|
270
|
-
propExist(iconLeft) ? 'rounded-start-0' : 'rounded',
|
|
271
|
-
clsWrite(controlClassName, 'form-control ')
|
|
272
|
-
)}
|
|
273
|
-
id={idRes}
|
|
274
|
-
name={name}
|
|
275
|
-
step={step || null}
|
|
276
|
-
min={min || null}
|
|
277
|
-
max={max || null}
|
|
278
|
-
src={src || null}
|
|
279
|
-
size={size || null}
|
|
280
|
-
alt={alt || null}
|
|
281
|
-
inputMode={inputMode || 'text'}
|
|
282
|
-
pattern={pattern || null}
|
|
283
|
-
placeholder={placeholder || ''}
|
|
284
|
-
defaultValue={defaultValue}
|
|
285
|
-
value={changedVal}
|
|
286
|
-
minLength={minLength || null}
|
|
287
|
-
maxLength={maxLength || null}
|
|
288
|
-
autoComplete={typeof autoComplete === 'undefined' ? 'on' : autoComplete}
|
|
289
|
-
autoCapitalize={typeof autoCapitalize === 'undefined' ? 'off' : autoCapitalize}
|
|
290
|
-
spellCheck={typeof spellCheck === 'undefined' ? false : spellCheck}
|
|
291
|
-
onFocus={handleFocus}
|
|
292
|
-
onBlur={handleBlur}
|
|
293
|
-
onChange={handleChange}
|
|
294
|
-
onKeyDown={handleKeyPressed}
|
|
295
|
-
onCompositionStart={handleComposition}
|
|
296
|
-
onCompositionUpdate={handleComposition}
|
|
297
|
-
onCompositionEnd={handleComposition}
|
|
298
|
-
disabled={disabled || null}
|
|
299
|
-
required={required || null}
|
|
300
|
-
readOnly={readOnly || null}
|
|
301
|
-
style={style}
|
|
302
|
-
{...attributes}
|
|
303
|
-
/>
|
|
304
|
-
{appendControl || ''}
|
|
305
|
-
{propExist(units) ? <><span className={clsWrite(controlGroupTextClassName, 'input-group-text')}>{units}</span></> : null}
|
|
306
|
-
{propExist(iconRight) ? <><span className={clsWrite(controlGroupTextClassName, 'input-group-text')}>{iconRight}</span></> : null}
|
|
307
|
-
</div>
|
|
308
|
-
|
|
309
|
-
</> : <>
|
|
310
|
-
|
|
496
|
+
{propExist(iconLeft) ? <><span className={clsWrite(controlGroupTextClassName, 'input-group-text')}>{iconLeft}</span></> : null}
|
|
311
497
|
|
|
498
|
+
<div className="input-group-control-container flex-fill position-relative">
|
|
312
499
|
<input
|
|
313
500
|
ref={(node) => {
|
|
314
501
|
valRef.current = node;
|
|
@@ -318,14 +505,16 @@ const Input = forwardRef((props: InputProps, externalRef: any) => {
|
|
|
318
505
|
externalRef.current = node;
|
|
319
506
|
}
|
|
320
507
|
}}
|
|
321
|
-
|
|
508
|
+
|
|
322
509
|
tabIndex={tabIndex || 0}
|
|
323
510
|
type={typeRes}
|
|
324
511
|
className={combinedCls(
|
|
325
512
|
clsWrite(controlClassName, 'form-control'),
|
|
326
513
|
controlExClassName,
|
|
327
514
|
{
|
|
328
|
-
'rounded': !propExist(iconLeft) && !propExist(iconRight) && !propExist(units)
|
|
515
|
+
'rounded': !propExist(iconLeft) && !propExist(iconRight) && !propExist(units),
|
|
516
|
+
'rounded-start-0': propExist(iconLeft),
|
|
517
|
+
'rounded-end-0': propExist(iconRight) || propExist(units)
|
|
329
518
|
}
|
|
330
519
|
)}
|
|
331
520
|
id={idRes}
|
|
@@ -347,7 +536,15 @@ const Input = forwardRef((props: InputProps, externalRef: any) => {
|
|
|
347
536
|
spellCheck={typeof spellCheck === 'undefined' ? false : spellCheck}
|
|
348
537
|
onFocus={handleFocus}
|
|
349
538
|
onBlur={handleBlur}
|
|
350
|
-
onChange={
|
|
539
|
+
onChange={(e: any) => {
|
|
540
|
+
handleChange(e);
|
|
541
|
+
|
|
542
|
+
// AI Predict
|
|
543
|
+
if (aiPredict) {
|
|
544
|
+
handleChangeSuggestionsFetchSafe(e, e.target.value);
|
|
545
|
+
}
|
|
546
|
+
|
|
547
|
+
}}
|
|
351
548
|
onKeyDown={handleKeyPressed}
|
|
352
549
|
onCompositionStart={handleComposition}
|
|
353
550
|
onCompositionUpdate={handleComposition}
|
|
@@ -358,16 +555,41 @@ const Input = forwardRef((props: InputProps, externalRef: any) => {
|
|
|
358
555
|
style={style}
|
|
359
556
|
{...attributes}
|
|
360
557
|
/>
|
|
558
|
+
|
|
361
559
|
{appendControl || ''}
|
|
362
|
-
|
|
363
|
-
{
|
|
560
|
+
|
|
561
|
+
{/* AI Predict */}
|
|
562
|
+
{aiPredict && remainingText && (
|
|
563
|
+
<div
|
|
564
|
+
ref={aiInputRef}
|
|
565
|
+
className="position-absolute z-1"
|
|
566
|
+
style={{
|
|
567
|
+
left: `${originInputComputedStyle.current.fontSize + textWidth}px`,
|
|
568
|
+
top: originInputComputedStyle.current.textTop + 'px',
|
|
569
|
+
color: `rgba(${aiPredictRemainingTextRGB[0]}, ${aiPredictRemainingTextRGB[1]}, ${aiPredictRemainingTextRGB[2]}, ${calculateOpacity()})`,
|
|
570
|
+
pointerEvents: 'none',
|
|
571
|
+
fontSize: originInputComputedStyle.current.fontSize + 'px',
|
|
572
|
+
fontFamily: originInputComputedStyle.current.fontFamily,
|
|
573
|
+
letterSpacing: originInputComputedStyle.current.letterSpacing
|
|
574
|
+
}}
|
|
575
|
+
>
|
|
576
|
+
{remainingText}
|
|
577
|
+
</div>
|
|
578
|
+
)}
|
|
579
|
+
|
|
580
|
+
{/* Required marking */}
|
|
581
|
+
{required ? <>{requiredLabel || requiredLabel === '' ? requiredLabel : <span className="position-absolute end-0 top-0 my-2 mx-2"><span className="text-danger">*</span></span>}</> : ''}
|
|
582
|
+
|
|
583
|
+
</div>
|
|
364
584
|
|
|
365
585
|
|
|
366
|
-
|
|
586
|
+
{propExist(units) ? <><span className={clsWrite(controlGroupTextClassName, 'input-group-text')}>{units}</span></> : null}
|
|
587
|
+
{propExist(iconRight) ? <><span className={clsWrite(controlGroupTextClassName, 'input-group-text')}>{iconRight}</span></> : null}
|
|
588
|
+
|
|
367
589
|
|
|
368
|
-
|
|
369
590
|
</div>
|
|
370
|
-
|
|
591
|
+
|
|
592
|
+
|
|
371
593
|
|
|
372
594
|
</div>
|
|
373
595
|
|
|
@@ -87,15 +87,22 @@ const MasonryLayout = (props: MasonryLayoutProps) => {
|
|
|
87
87
|
items = children;
|
|
88
88
|
}
|
|
89
89
|
|
|
90
|
+
// get wrapper width
|
|
91
|
+
const wrapperWidth = rootRef.current?.offsetWidth || 0;
|
|
92
|
+
const perBrickWidth = wrapperWidth/colCount; // Prevent the width of the internal elements from overflowing
|
|
93
|
+
|
|
94
|
+
|
|
90
95
|
items.forEach((el: React.ReactNode, i: number) => {
|
|
91
96
|
const columnIndex = i % colCount;
|
|
92
97
|
columnWrapper[`${itemWrapperKey}${columnIndex}`].push(
|
|
93
98
|
<div
|
|
94
99
|
key={i}
|
|
95
100
|
className="masonry-item"
|
|
96
|
-
style={{
|
|
101
|
+
style={{
|
|
102
|
+
marginBottom: `${GAP}px`
|
|
103
|
+
}}
|
|
97
104
|
>
|
|
98
|
-
{el}
|
|
105
|
+
<div style={perBrickWidth > 0 ? {maxWidth: perBrickWidth + 'px'} : undefined}>{el}</div>
|
|
99
106
|
</div>
|
|
100
107
|
);
|
|
101
108
|
});
|
|
@@ -40,6 +40,7 @@ export type MultipleSelectProps = {
|
|
|
40
40
|
availableHeaderTitle?: string;
|
|
41
41
|
selectedHeaderTitle?: string;
|
|
42
42
|
selectedHeaderNote?: string;
|
|
43
|
+
selectedResultReverse?: boolean;
|
|
43
44
|
removeAllBtnLabel?: string | React.ReactNode;
|
|
44
45
|
addAllBtnLabel?: string | React.ReactNode;
|
|
45
46
|
iconAdd?: React.ReactNode | string;
|
|
@@ -88,6 +89,7 @@ const MultipleSelect = forwardRef((props: MultipleSelectProps, externalRef: any)
|
|
|
88
89
|
availableHeaderTitle,
|
|
89
90
|
selectedHeaderTitle,
|
|
90
91
|
selectedHeaderNote,
|
|
92
|
+
selectedResultReverse = false,
|
|
91
93
|
removeAllBtnLabel,
|
|
92
94
|
addAllBtnLabel,
|
|
93
95
|
iconAdd,
|
|
@@ -314,7 +316,7 @@ const MultipleSelect = forwardRef((props: MultipleSelectProps, externalRef: any)
|
|
|
314
316
|
const index = newData.findIndex((item: string | number) => item == _val);
|
|
315
317
|
if (index !== -1) newData.splice(index, 1);
|
|
316
318
|
|
|
317
|
-
const _res = (_val) ? Array.from(new Set([
|
|
319
|
+
const _res = (_val) ? Array.from(new Set([...newData, _val])) : newData;
|
|
318
320
|
onChange?.(_li, _res, VALUE_BY_BRACKETS ? convertArrToValByBrackets(_res) : _res.join(','), _data, 'add');
|
|
319
321
|
|
|
320
322
|
// hide current item
|
|
@@ -330,7 +332,7 @@ const MultipleSelect = forwardRef((props: MultipleSelectProps, externalRef: any)
|
|
|
330
332
|
const index = newData.findIndex((item: any) => item.value == _val);
|
|
331
333
|
if (index !== -1) newData.splice(index, 1);
|
|
332
334
|
|
|
333
|
-
const _res = (_val) ? Array.from(new Set([
|
|
335
|
+
const _res = (_val) ? Array.from(new Set([...newData, _data])) : newData;
|
|
334
336
|
|
|
335
337
|
|
|
336
338
|
return _res;
|
|
@@ -596,13 +598,13 @@ const MultipleSelect = forwardRef((props: MultipleSelectProps, externalRef: any)
|
|
|
596
598
|
listContainerClassName="m-select__selected m-select__options-contentlist--sortable m-select__options-contentlist"
|
|
597
599
|
ref={selectedListRef}
|
|
598
600
|
indentStr={INDENT_LAST_PLACEHOLDER}
|
|
599
|
-
valSelected={valSelected}
|
|
601
|
+
valSelected={selectedResultReverse ? valSelected.reverse() : valSelected}
|
|
600
602
|
iconRemove={iconRemove}
|
|
601
603
|
onSelect={removeItem}
|
|
602
604
|
alternateCollapse={alternateCollapse}
|
|
603
605
|
first={true}
|
|
604
606
|
arrow={arrow}
|
|
605
|
-
data={valSelectedData}
|
|
607
|
+
data={selectedResultReverse ? valSelectedData.reverse() : valSelectedData}
|
|
606
608
|
childClassName={clsWrite(childClassName, 'm-select__options-contentlist--custom')}
|
|
607
609
|
selected
|
|
608
610
|
/>
|
package/lib/esm/Table/Table.tsx
CHANGED
|
@@ -5,7 +5,6 @@ import useComId from 'funda-utils/dist/cjs/useComId';
|
|
|
5
5
|
import { clsWrite, combinedCls } from 'funda-utils/dist/cjs/cls';
|
|
6
6
|
|
|
7
7
|
|
|
8
|
-
|
|
9
8
|
import { TableProvider } from './TableContext';
|
|
10
9
|
import useTableResponsive from './utils/hooks/useTableResponsive';
|
|
11
10
|
import useTableDraggable from './utils/hooks/useTableDraggable';
|
package/lib/esm/Table/index.scss
CHANGED
|
@@ -15,6 +15,7 @@
|
|
|
15
15
|
|
|
16
16
|
&.table-responsive {
|
|
17
17
|
overflow-x: auto;
|
|
18
|
+
overflow-y: hidden;
|
|
18
19
|
|
|
19
20
|
&::-webkit-scrollbar {
|
|
20
21
|
height: var(--syntable-scrollbar-h);
|
|
@@ -164,6 +165,7 @@
|
|
|
164
165
|
|
|
165
166
|
.row-obj-clonelast {
|
|
166
167
|
height: 0 !important;
|
|
168
|
+
|
|
167
169
|
|
|
168
170
|
td {
|
|
169
171
|
border: none;
|