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
|
@@ -64,7 +64,7 @@ function useTableDraggable({
|
|
|
64
64
|
|
|
65
65
|
const placeholderGenerator = (trHeight: number) => {
|
|
66
66
|
const tbodyRef: any = getTbody(spyElement);
|
|
67
|
-
if (tbodyRef === null) return;
|
|
67
|
+
if (tbodyRef === null || tbodyRef.querySelector('tr') === null) return;
|
|
68
68
|
|
|
69
69
|
// Insert a row at the "index" of the table
|
|
70
70
|
const newRow = document.createElement('tr');
|
|
@@ -85,7 +85,11 @@ function useTableDraggable({
|
|
|
85
85
|
|
|
86
86
|
const lastRowGenerator = (trHeight: number) => {
|
|
87
87
|
const tbodyRef: any = getTbody(spyElement);
|
|
88
|
-
if (tbodyRef === null) return;
|
|
88
|
+
if (tbodyRef === null || tbodyRef.querySelector('tr') === null) return;
|
|
89
|
+
|
|
90
|
+
const cloneEl = tbodyRef.querySelector('.row-obj-clonelast');
|
|
91
|
+
if (cloneEl !== null) return;
|
|
92
|
+
|
|
89
93
|
|
|
90
94
|
// Insert a row at the "index" of the table
|
|
91
95
|
const newRow = document.createElement('tr');
|
|
@@ -93,6 +97,7 @@ function useTableDraggable({
|
|
|
93
97
|
newRow.dataset.order = allRows(spyElement).length.toString();
|
|
94
98
|
newRow.style.height = trHeight + 'px';
|
|
95
99
|
newRow.style.display = 'none';
|
|
100
|
+
|
|
96
101
|
|
|
97
102
|
// Insert a cell in the row at index
|
|
98
103
|
const newCell = newRow.insertCell(0);
|
|
@@ -134,7 +139,14 @@ function useTableDraggable({
|
|
|
134
139
|
setSortData(listIndexes);
|
|
135
140
|
|
|
136
141
|
//last placeholder
|
|
137
|
-
|
|
142
|
+
if (_allRows.length > 0) {
|
|
143
|
+
const lastEl: any = lastRowGenerator((_allRows.at(-1) as any).clientHeight);
|
|
144
|
+
if (typeof _allRows.at(-1) !== 'undefined') {
|
|
145
|
+
insertAfter(lastEl, _allRows.at(-1));
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
|
|
138
150
|
};
|
|
139
151
|
|
|
140
152
|
const handleTbodyEnter = (e: any) => {
|
|
@@ -182,6 +194,9 @@ function useTableDraggable({
|
|
|
182
194
|
|
|
183
195
|
|
|
184
196
|
const handleDragStart = useCallback((e: any) => {
|
|
197
|
+
const tbodyRef: any = getTbody(spyElement);
|
|
198
|
+
if (tbodyRef === null) return;
|
|
199
|
+
|
|
185
200
|
draggedObj = e.currentTarget;
|
|
186
201
|
e.dataTransfer.effectAllowed = 'move';
|
|
187
202
|
e.dataTransfer.setData('text/html', draggedObj);
|
|
@@ -196,6 +211,15 @@ function useTableDraggable({
|
|
|
196
211
|
};
|
|
197
212
|
onRowDrag?.(dragStart, null);
|
|
198
213
|
|
|
214
|
+
|
|
215
|
+
// init clone <tr>
|
|
216
|
+
// !!! It needs to be put at the end of the code to fix the location of the clone element
|
|
217
|
+
const cloneEl = tbodyRef.querySelector('.row-obj-clonelast');
|
|
218
|
+
if (cloneEl !== null) {
|
|
219
|
+
cloneEl.style.display = 'none';
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
|
|
199
223
|
}, [handledragOver]);
|
|
200
224
|
|
|
201
225
|
const handleDragEnd = useCallback((e: any) => {
|
|
@@ -250,9 +274,12 @@ function useTableDraggable({
|
|
|
250
274
|
// sort elements
|
|
251
275
|
const categoryItemsArray = allRows(spyElement);
|
|
252
276
|
const sorter = (a: any, b: any) => {
|
|
253
|
-
|
|
277
|
+
let txt1 = Number(a.dataset.order),
|
|
278
|
+
txt2 = Number(b.dataset.order);
|
|
279
|
+
|
|
280
|
+
return txt2 < txt1 ? -1 : txt2 > txt1 ? 1 : 0;
|
|
254
281
|
}
|
|
255
|
-
const sorted = categoryItemsArray.sort(sorter);
|
|
282
|
+
const sorted = categoryItemsArray.sort(sorter).reverse();
|
|
256
283
|
sorted.forEach(e => spyElement.querySelector('table').querySelector('tbody').appendChild(e));
|
|
257
284
|
|
|
258
285
|
|
|
@@ -264,13 +291,27 @@ function useTableDraggable({
|
|
|
264
291
|
|
|
265
292
|
|
|
266
293
|
|
|
294
|
+
// init clone <tr>
|
|
295
|
+
// !!! It needs to be put at the end of the code to fix the location of the clone element
|
|
296
|
+
const _allRows = allRows(spyElement);
|
|
297
|
+
const cloneEl = tbodyRef.querySelector('.row-obj-clonelast');
|
|
298
|
+
if (cloneEl !== null) {
|
|
299
|
+
if (typeof _allRows.at(-1) !== 'undefined') {
|
|
300
|
+
insertAfter(cloneEl, _allRows.at(-1));
|
|
301
|
+
cloneEl.style.display = 'none';
|
|
302
|
+
}
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
|
|
306
|
+
|
|
267
307
|
}, [sortData]);
|
|
268
308
|
|
|
269
309
|
|
|
270
310
|
|
|
271
311
|
useEffect(() => {
|
|
272
312
|
if (enabled) {
|
|
273
|
-
if (Array.isArray(data)) {
|
|
313
|
+
if (Array.isArray(data) && data.length > 0) {
|
|
314
|
+
// !!! REQUIRED "data.length > 0" to avoid data-order cannot be assigned when asynchronous data is empty
|
|
274
315
|
data.forEach((item: any, i: number) => {
|
|
275
316
|
item.order = i;
|
|
276
317
|
});
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import React, { useState, useEffect, useRef, forwardRef, ChangeEvent, MouseEvent, KeyboardEvent, FocusEvent, CompositionEvent } from 'react';
|
|
1
|
+
import React, { useState, useEffect, useRef, forwardRef, useImperativeHandle, ChangeEvent, MouseEvent, KeyboardEvent, FocusEvent, CompositionEvent } from 'react';
|
|
2
2
|
|
|
3
3
|
|
|
4
4
|
|
|
@@ -14,6 +14,7 @@ import { clsWrite, combinedCls } from 'funda-utils/dist/cjs/cls';
|
|
|
14
14
|
|
|
15
15
|
|
|
16
16
|
export type TagInputProps = {
|
|
17
|
+
contentRef?: React.ForwardedRef<any>;
|
|
17
18
|
wrapperClassName?: string;
|
|
18
19
|
value?: string;
|
|
19
20
|
maxTags?: number;
|
|
@@ -45,6 +46,7 @@ export type TagInputProps = {
|
|
|
45
46
|
|
|
46
47
|
const TagInput = forwardRef((props: TagInputProps, externalRef: any) => {
|
|
47
48
|
const {
|
|
49
|
+
contentRef,
|
|
48
50
|
wrapperClassName,
|
|
49
51
|
maxTags,
|
|
50
52
|
disabled,
|
|
@@ -85,6 +87,26 @@ const TagInput = forwardRef((props: TagInputProps, externalRef: any) => {
|
|
|
85
87
|
const [onComposition, setOnComposition] = useState<boolean>(false);
|
|
86
88
|
|
|
87
89
|
|
|
90
|
+
// exposes the following methods
|
|
91
|
+
useImperativeHandle(
|
|
92
|
+
contentRef,
|
|
93
|
+
() => ({
|
|
94
|
+
control: () => {
|
|
95
|
+
return valRef.current;
|
|
96
|
+
},
|
|
97
|
+
clear: (cb?: any) => {
|
|
98
|
+
initDefaultValue('');
|
|
99
|
+
cb?.();
|
|
100
|
+
},
|
|
101
|
+
set: (value: string, cb?: any) => {
|
|
102
|
+
initDefaultValue(`${value}`);
|
|
103
|
+
cb?.();
|
|
104
|
+
}
|
|
105
|
+
}),
|
|
106
|
+
[contentRef],
|
|
107
|
+
);
|
|
108
|
+
|
|
109
|
+
|
|
88
110
|
function initDefaultValue(defaultValue: any) {
|
|
89
111
|
|
|
90
112
|
// change the value to trigger component rendering
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import React, { useState, useEffect, useRef, forwardRef, KeyboardEvent, useImperativeHandle } from 'react';
|
|
2
2
|
|
|
3
3
|
|
|
4
|
-
|
|
5
4
|
import useComId from 'funda-utils/dist/cjs/useComId';
|
|
6
5
|
import useAutosizeTextArea from 'funda-utils/dist/cjs/useAutosizeTextArea';
|
|
7
6
|
import { clsWrite, combinedCls } from 'funda-utils/dist/cjs/cls';
|
|
8
|
-
|
|
7
|
+
import { actualPropertyValue, getTextTop } from 'funda-utils/dist/cjs/inputsCalculation';
|
|
8
|
+
import useDebounce from 'funda-utils/dist/cjs/useDebounce';
|
|
9
9
|
|
|
10
10
|
|
|
11
11
|
export type TextareaProps = {
|
|
@@ -31,6 +31,13 @@ export type TextareaProps = {
|
|
|
31
31
|
autoSize?: boolean;
|
|
32
32
|
iconLeft?: React.ReactNode | string;
|
|
33
33
|
iconRight?: React.ReactNode | string;
|
|
34
|
+
aiPredict?: boolean;
|
|
35
|
+
aiPredictRemainingTextRGB?: number[];
|
|
36
|
+
aiPredictConfirmKey?: Array<string[]>;
|
|
37
|
+
aiPredictFetchFuncAsync?: any;
|
|
38
|
+
aiPredictFetchFuncMethod?: string;
|
|
39
|
+
aiPredictFetchFuncMethodParams?: any[];
|
|
40
|
+
aiPredictFetchCallback?: (data: any) => void;
|
|
34
41
|
/** -- */
|
|
35
42
|
id?: string;
|
|
36
43
|
style?: React.CSSProperties;
|
|
@@ -64,6 +71,13 @@ const Textarea = forwardRef((props: TextareaProps, externalRef: any) => {
|
|
|
64
71
|
autoSize,
|
|
65
72
|
iconLeft,
|
|
66
73
|
iconRight,
|
|
74
|
+
aiPredict = false,
|
|
75
|
+
aiPredictRemainingTextRGB = [153, 153, 153],
|
|
76
|
+
aiPredictConfirmKey = [['Enter'],['Tab'],['Shift', ' ']],
|
|
77
|
+
aiPredictFetchFuncAsync,
|
|
78
|
+
aiPredictFetchFuncMethod,
|
|
79
|
+
aiPredictFetchFuncMethodParams,
|
|
80
|
+
aiPredictFetchCallback,
|
|
67
81
|
readOnly,
|
|
68
82
|
defaultValue,
|
|
69
83
|
value,
|
|
@@ -93,6 +107,173 @@ const Textarea = forwardRef((props: TextareaProps, externalRef: any) => {
|
|
|
93
107
|
const valRef = useRef<any>(null);
|
|
94
108
|
const [changedVal, setChangedVal] = useState<string>(value || '');
|
|
95
109
|
|
|
110
|
+
|
|
111
|
+
//================================================================
|
|
112
|
+
// AI Predict
|
|
113
|
+
//================================================================
|
|
114
|
+
const [currentSuggestion, setCurrentSuggestion] = useState<string>('');
|
|
115
|
+
const [tempMatchedSuggestion, setTempMatchedSuggestion] = useState<string[]>([]);
|
|
116
|
+
const [textWidth, setTextWidth] = useState<number>(0);
|
|
117
|
+
const aiInputRef = useRef<any>(null);
|
|
118
|
+
const originInputComputedStyle = useRef<Record<string, any>>({
|
|
119
|
+
fontSize: 16,
|
|
120
|
+
fontFamily: 'inherit',
|
|
121
|
+
letterSpacing: 'normal',
|
|
122
|
+
textTop: 10
|
|
123
|
+
});
|
|
124
|
+
const [hasErr, setHasErr] = useState<boolean>(false);
|
|
125
|
+
const currentSuggestionIndex = useRef<number>(0);
|
|
126
|
+
|
|
127
|
+
|
|
128
|
+
|
|
129
|
+
// A list of suggestions
|
|
130
|
+
//----------------
|
|
131
|
+
const [suggestions, setSuggestions] = useState<string[]>([]);
|
|
132
|
+
|
|
133
|
+
//performance
|
|
134
|
+
const handleChangeSuggestionsFetchSafe = useDebounce((e: any, curVal: string) => {
|
|
135
|
+
const _oparams: any[] = aiPredictFetchFuncMethodParams || [];
|
|
136
|
+
const _params: any[] = _oparams.map((item: any) => item !== '$QUERY_STRING' ? item : curVal);
|
|
137
|
+
fetchSuggestionsData((_params).join(',')).then((resSuggestions: string[]) => {
|
|
138
|
+
handleInputAiPredictChange(curVal, resSuggestions);
|
|
139
|
+
});
|
|
140
|
+
}, 350, []);
|
|
141
|
+
|
|
142
|
+
async function fetchSuggestionsData(params: any) {
|
|
143
|
+
|
|
144
|
+
if (typeof aiPredictFetchFuncAsync === 'object') {
|
|
145
|
+
|
|
146
|
+
const response: any = await aiPredictFetchFuncAsync[`${aiPredictFetchFuncMethod}`](...params.split(','));
|
|
147
|
+
let _ORGIN_DATA = response.data;
|
|
148
|
+
|
|
149
|
+
// reset data structure
|
|
150
|
+
if (typeof (aiPredictFetchCallback) === 'function') {
|
|
151
|
+
_ORGIN_DATA = aiPredictFetchCallback(_ORGIN_DATA);
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
// Determine whether the data structure matches
|
|
155
|
+
if (!Array.isArray(_ORGIN_DATA)) {
|
|
156
|
+
console.warn('The data structure does not match, please refer to the example in the component documentation.');
|
|
157
|
+
setHasErr(true);
|
|
158
|
+
_ORGIN_DATA = [];
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
//
|
|
162
|
+
setSuggestions(_ORGIN_DATA);
|
|
163
|
+
|
|
164
|
+
return _ORGIN_DATA;
|
|
165
|
+
} else {
|
|
166
|
+
return [];
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
|
|
173
|
+
|
|
174
|
+
// Calculates the width of the input text
|
|
175
|
+
//----------------
|
|
176
|
+
const calculateTextWidth = (text: string) => {
|
|
177
|
+
if (valRef.current) {
|
|
178
|
+
const canvas = document.createElement('canvas');
|
|
179
|
+
const context: any = canvas.getContext('2d');
|
|
180
|
+
context.font = `${originInputComputedStyle.current.fontSize}px ${originInputComputedStyle.current.fontFamily}`;
|
|
181
|
+
return context.measureText(text).width;
|
|
182
|
+
}
|
|
183
|
+
return 0;
|
|
184
|
+
};
|
|
185
|
+
|
|
186
|
+
|
|
187
|
+
|
|
188
|
+
// Get the rest of the suggested text
|
|
189
|
+
//----------------
|
|
190
|
+
const getRemainingText = (fullSuggestion: string) => {
|
|
191
|
+
if (!changedVal || !fullSuggestion) return '';
|
|
192
|
+
|
|
193
|
+
|
|
194
|
+
// Only the parts of the suggested text that were not entered are returned
|
|
195
|
+
const lastInputChar = changedVal[changedVal.length - 1];
|
|
196
|
+
const lastCharIndex = fullSuggestion.toLowerCase().lastIndexOf(lastInputChar.toLowerCase());
|
|
197
|
+
return fullSuggestion.slice(lastCharIndex + 1);
|
|
198
|
+
|
|
199
|
+
};
|
|
200
|
+
|
|
201
|
+
// Match exactly from the start
|
|
202
|
+
//----------------
|
|
203
|
+
const preciseMatch = (input: any, suggestions: string[]) => {
|
|
204
|
+
if (!input) return '';
|
|
205
|
+
|
|
206
|
+
const filtered = suggestions.filter(s =>
|
|
207
|
+
s.toLowerCase().startsWith(input.toLowerCase())
|
|
208
|
+
);
|
|
209
|
+
|
|
210
|
+
setTempMatchedSuggestion(filtered);
|
|
211
|
+
return filtered;
|
|
212
|
+
};
|
|
213
|
+
|
|
214
|
+
|
|
215
|
+
// Fuzzy matching
|
|
216
|
+
//----------------
|
|
217
|
+
const fuzzyMatch = (input: any, suggestions: string[]) => {
|
|
218
|
+
if (!input) return '';
|
|
219
|
+
|
|
220
|
+
// Convert input to a regular expression pattern with support for arbitrary position matching
|
|
221
|
+
const pattern = input.split('').map((char: string) =>
|
|
222
|
+
char.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')
|
|
223
|
+
).join('.*');
|
|
224
|
+
const regex = new RegExp(pattern, 'i');
|
|
225
|
+
|
|
226
|
+
// Find the first matching suggestion (multiple matches)
|
|
227
|
+
const filtered = suggestions.filter((suggestion: string) => regex.test(suggestion));
|
|
228
|
+
setTempMatchedSuggestion(filtered);
|
|
229
|
+
return filtered;
|
|
230
|
+
};
|
|
231
|
+
|
|
232
|
+
// Handle input variations
|
|
233
|
+
//----------------
|
|
234
|
+
const handleInputAiPredictChange = (newValue: string, curSuggestions: string[]) => {
|
|
235
|
+
setTextWidth(calculateTextWidth(newValue));
|
|
236
|
+
|
|
237
|
+
// Match results
|
|
238
|
+
const matchedSuggestion = fuzzyMatch(newValue, curSuggestions);
|
|
239
|
+
setCurrentSuggestion(matchedSuggestion[0] || '');
|
|
240
|
+
|
|
241
|
+
};
|
|
242
|
+
|
|
243
|
+
|
|
244
|
+
|
|
245
|
+
|
|
246
|
+
// Calculate the color shade of the prompt text
|
|
247
|
+
//----------------
|
|
248
|
+
const calculateOpacity = () => {
|
|
249
|
+
// Transparency is calculated based on the input length
|
|
250
|
+
const baseOpacity = 0.5;
|
|
251
|
+
const inputLength = changedVal.length;
|
|
252
|
+
return Math.max(0.2, baseOpacity - (inputLength * 0.05));
|
|
253
|
+
};
|
|
254
|
+
|
|
255
|
+
|
|
256
|
+
// Confirm
|
|
257
|
+
//----------------
|
|
258
|
+
const handleAiPredictKeyDown = (e: KeyboardEvent<HTMLTextAreaElement>) => {
|
|
259
|
+
// Prevents the default behavior of the enter key
|
|
260
|
+
e.preventDefault();
|
|
261
|
+
|
|
262
|
+
const remainingText = getRemainingText(currentSuggestion);
|
|
263
|
+
if (remainingText) {
|
|
264
|
+
// Only the second half of the text is added
|
|
265
|
+
setChangedVal(changedVal + remainingText);
|
|
266
|
+
setCurrentSuggestion('');
|
|
267
|
+
}
|
|
268
|
+
};
|
|
269
|
+
|
|
270
|
+
//
|
|
271
|
+
const remainingText = getRemainingText(currentSuggestion);
|
|
272
|
+
|
|
273
|
+
|
|
274
|
+
//================================================================
|
|
275
|
+
// General
|
|
276
|
+
//================================================================
|
|
96
277
|
// exposes the following methods
|
|
97
278
|
useImperativeHandle(
|
|
98
279
|
contentRef,
|
|
@@ -121,6 +302,12 @@ const Textarea = forwardRef((props: TextareaProps, externalRef: any) => {
|
|
|
121
302
|
onResize?.(valRef.current, res);
|
|
122
303
|
}
|
|
123
304
|
});
|
|
305
|
+
|
|
306
|
+
|
|
307
|
+
const propExist = (p: any) => {
|
|
308
|
+
return typeof p !== 'undefined' && p !== null && p !== '';
|
|
309
|
+
};
|
|
310
|
+
|
|
124
311
|
|
|
125
312
|
function handleFocus(event: any) {
|
|
126
313
|
const el = event.target;
|
|
@@ -130,6 +317,7 @@ const Textarea = forwardRef((props: TextareaProps, externalRef: any) => {
|
|
|
130
317
|
onFocus?.(event, valRef.current);
|
|
131
318
|
}
|
|
132
319
|
|
|
320
|
+
|
|
133
321
|
function handleChange(event: any) {
|
|
134
322
|
const val = event.target.value;
|
|
135
323
|
|
|
@@ -186,6 +374,49 @@ const Textarea = forwardRef((props: TextareaProps, externalRef: any) => {
|
|
|
186
374
|
onPressEnter?.(event, valRef.current);
|
|
187
375
|
}
|
|
188
376
|
|
|
377
|
+
// AI Predict
|
|
378
|
+
//----
|
|
379
|
+
if (aiPredict && currentSuggestion !== '') {
|
|
380
|
+
const keyBindings: Array<string[]> = aiPredictConfirmKey;
|
|
381
|
+
// The parameter 'registerKeyEvents' is an array, and each element is an object
|
|
382
|
+
// eg. { keys: ["Control", "S"], action: () => { console.log("Ctrl+S"); } }
|
|
383
|
+
const registerKeyEvents: Record<string, any>[] = keyBindings.map((s: string[]) => {
|
|
384
|
+
return {
|
|
385
|
+
keys: s,
|
|
386
|
+
action: () => {
|
|
387
|
+
handleAiPredictKeyDown(event);
|
|
388
|
+
},
|
|
389
|
+
};
|
|
390
|
+
});
|
|
391
|
+
|
|
392
|
+
registerKeyEvents.forEach((binding: Record<string, any>) => {
|
|
393
|
+
const keysPressed = binding.keys.every((key: string) =>
|
|
394
|
+
key === "Shift" ? event.shiftKey :
|
|
395
|
+
key === "Control" ? event.ctrlKey :
|
|
396
|
+
key === "Alt" ? event.altKey :
|
|
397
|
+
key === "Meta" ? event.metaKey :
|
|
398
|
+
event.key === key
|
|
399
|
+
);
|
|
400
|
+
|
|
401
|
+
if (keysPressed) {
|
|
402
|
+
binding.action();
|
|
403
|
+
}
|
|
404
|
+
});
|
|
405
|
+
|
|
406
|
+
|
|
407
|
+
// switch result of suggestions
|
|
408
|
+
if (event.code === 'ArrowUp') {
|
|
409
|
+
currentSuggestionIndex.current = (currentSuggestionIndex.current - 1 + tempMatchedSuggestion.length) % tempMatchedSuggestion.length;
|
|
410
|
+
}
|
|
411
|
+
|
|
412
|
+
if (event.code === 'ArrowDown') {
|
|
413
|
+
currentSuggestionIndex.current = (currentSuggestionIndex.current + 1) % tempMatchedSuggestion.length;
|
|
414
|
+
}
|
|
415
|
+
setCurrentSuggestion(tempMatchedSuggestion[currentSuggestionIndex.current] || '');
|
|
416
|
+
|
|
417
|
+
}
|
|
418
|
+
|
|
419
|
+
|
|
189
420
|
}
|
|
190
421
|
|
|
191
422
|
|
|
@@ -234,6 +465,19 @@ const Textarea = forwardRef((props: TextareaProps, externalRef: any) => {
|
|
|
234
465
|
}
|
|
235
466
|
}
|
|
236
467
|
|
|
468
|
+
// AI Predict initalization
|
|
469
|
+
//--------------
|
|
470
|
+
if (aiPredict && valRef.current !== null) {
|
|
471
|
+
originInputComputedStyle.current = {
|
|
472
|
+
fontSize: actualPropertyValue(valRef.current as HTMLInputElement, 'fontSize'),
|
|
473
|
+
fontFamily: actualPropertyValue(valRef.current as HTMLInputElement, 'fontFamily'),
|
|
474
|
+
letterSpacing: actualPropertyValue(valRef.current as HTMLInputElement, 'letterSpacing'),
|
|
475
|
+
textTop: getTextTop(valRef.current)
|
|
476
|
+
};
|
|
477
|
+
}
|
|
478
|
+
|
|
479
|
+
|
|
480
|
+
|
|
237
481
|
}, []);
|
|
238
482
|
|
|
239
483
|
return (
|
|
@@ -242,45 +486,94 @@ const Textarea = forwardRef((props: TextareaProps, externalRef: any) => {
|
|
|
242
486
|
<div className={clsWrite(wrapperClassName, 'mb-3 position-relative')} ref={rootRef}>
|
|
243
487
|
{label ? <>{typeof label === 'string' ? <label htmlFor={idRes} className="form-label" dangerouslySetInnerHTML={{__html: `${label}`}}></label> : <label htmlFor={idRes} className="form-label">{label}</label>}</> : null}
|
|
244
488
|
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
489
|
+
|
|
490
|
+
<div className={combinedCls(
|
|
491
|
+
'position-relative z-1',
|
|
492
|
+
clsWrite(controlGroupWrapperClassName, 'input-group'),
|
|
493
|
+
{
|
|
494
|
+
'has-left-content': propExist(iconLeft),
|
|
495
|
+
'has-right-content': propExist(iconRight)
|
|
496
|
+
}
|
|
497
|
+
)}>
|
|
498
|
+
{propExist(iconLeft) ? <><span className={clsWrite(controlGroupTextClassName, 'input-group-text')}>{iconLeft}</span></> : null}
|
|
499
|
+
|
|
500
|
+
<div className="input-group-control-container flex-fill position-relative">
|
|
248
501
|
<textarea
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
502
|
+
ref={(node) => {
|
|
503
|
+
valRef.current = node;
|
|
504
|
+
if (typeof externalRef === 'function') {
|
|
505
|
+
externalRef(node);
|
|
506
|
+
} else if (externalRef) {
|
|
507
|
+
externalRef.current = node;
|
|
508
|
+
}
|
|
509
|
+
}}
|
|
510
|
+
tabIndex={tabIndex || 0}
|
|
511
|
+
className={combinedCls(
|
|
512
|
+
clsWrite(controlClassName, 'form-control'),
|
|
513
|
+
controlExClassName,
|
|
514
|
+
{
|
|
515
|
+
'rounded': !propExist(iconLeft) && !propExist(iconRight),
|
|
516
|
+
'rounded-start-0': propExist(iconLeft),
|
|
517
|
+
'rounded-end-0': propExist(iconRight)
|
|
518
|
+
}
|
|
519
|
+
)}
|
|
520
|
+
id={idRes}
|
|
521
|
+
name={name}
|
|
522
|
+
placeholder={placeholder || ''}
|
|
523
|
+
defaultValue={defaultValue}
|
|
524
|
+
value={changedVal}
|
|
525
|
+
minLength={minLength || null}
|
|
526
|
+
maxLength={maxLength || null}
|
|
527
|
+
onFocus={handleFocus}
|
|
528
|
+
onBlur={handleBlur}
|
|
529
|
+
onChange={(e: any) => {
|
|
530
|
+
handleChange(e);
|
|
531
|
+
|
|
532
|
+
// AI Predict
|
|
533
|
+
if (aiPredict) {
|
|
534
|
+
handleChangeSuggestionsFetchSafe(e, e.target.value);
|
|
535
|
+
}
|
|
536
|
+
}}
|
|
537
|
+
onKeyDown={handleKeyPressed}
|
|
538
|
+
disabled={disabled || null}
|
|
539
|
+
required={required || null}
|
|
540
|
+
readOnly={readOnly || null}
|
|
541
|
+
cols={cols || 20}
|
|
542
|
+
rows={rows || 2}
|
|
543
|
+
style={style}
|
|
544
|
+
{...attributes}
|
|
545
|
+
/>
|
|
546
|
+
|
|
547
|
+
{/* AI Predict */}
|
|
548
|
+
{aiPredict && remainingText && (
|
|
549
|
+
<div
|
|
550
|
+
ref={aiInputRef}
|
|
551
|
+
className="position-absolute z-1"
|
|
552
|
+
style={{
|
|
553
|
+
left: `${originInputComputedStyle.current.fontSize + textWidth}px`,
|
|
554
|
+
top: originInputComputedStyle.current.textTop + 'px',
|
|
555
|
+
color: `rgba(${aiPredictRemainingTextRGB[0]}, ${aiPredictRemainingTextRGB[1]}, ${aiPredictRemainingTextRGB[2]}, ${calculateOpacity()})`,
|
|
556
|
+
pointerEvents: 'none',
|
|
557
|
+
fontSize: originInputComputedStyle.current.fontSize + 'px',
|
|
558
|
+
fontFamily: originInputComputedStyle.current.fontFamily,
|
|
559
|
+
letterSpacing: originInputComputedStyle.current.letterSpacing
|
|
560
|
+
}}
|
|
561
|
+
>
|
|
562
|
+
{remainingText}
|
|
563
|
+
</div>
|
|
564
|
+
)}
|
|
565
|
+
|
|
566
|
+
{/* Required marking */}
|
|
567
|
+
{required ? <>{requiredLabel || requiredLabel === '' ? requiredLabel : <span className="position-absolute end-0 top-0 my-2 mx-2"><span className="text-danger">*</span></span>}</> : ''}
|
|
568
|
+
|
|
569
|
+
</div>
|
|
570
|
+
|
|
571
|
+
|
|
572
|
+
{propExist(iconRight) ? <><span className={clsWrite(controlGroupTextClassName, 'input-group-text')}>{iconRight}</span></> : null}
|
|
573
|
+
|
|
574
|
+
|
|
282
575
|
</div>
|
|
283
|
-
|
|
576
|
+
|
|
284
577
|
|
|
285
578
|
</div>
|
|
286
579
|
|
|
@@ -194,8 +194,9 @@ export default function TreeList(props: TreeListProps) {
|
|
|
194
194
|
function handleCollapse(e: any) {
|
|
195
195
|
if ( disableCollapse ) return;
|
|
196
196
|
|
|
197
|
-
|
|
198
197
|
e.preventDefault();
|
|
198
|
+
e.stopPropagation();
|
|
199
|
+
|
|
199
200
|
const hyperlink = e.currentTarget;
|
|
200
201
|
const url = hyperlink.getAttribute('href');
|
|
201
202
|
const subElement = getNextSiblings(hyperlink, 'ul');
|
|
@@ -258,6 +259,8 @@ export default function TreeList(props: TreeListProps) {
|
|
|
258
259
|
|
|
259
260
|
function handleSelect(e: any) {
|
|
260
261
|
e.preventDefault();
|
|
262
|
+
e.stopPropagation();
|
|
263
|
+
|
|
261
264
|
const hyperlink = e.currentTarget;
|
|
262
265
|
|
|
263
266
|
if ( hyperlink.classList.contains('selected') ) {
|