funda-ui 4.5.657 → 4.5.671

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.
Files changed (73) hide show
  1. package/ColorPicker/index.js +3 -1
  2. package/Date/index.d.ts +1 -0
  3. package/Date/index.js +17 -2
  4. package/DragDropList/index.css +188 -0
  5. package/DragDropList/index.d.ts +44 -0
  6. package/DragDropList/index.js +1587 -0
  7. package/Input/index.d.ts +2 -0
  8. package/Input/index.js +14 -1
  9. package/LICENSE +21 -0
  10. package/MasonryLayout/index.d.ts +2 -0
  11. package/MasonryLayout/index.js +115 -5
  12. package/MultipleSelect/index.css +237 -144
  13. package/MultipleSelect/index.d.ts +24 -10
  14. package/MultipleSelect/index.js +2240 -1225
  15. package/README.md +3 -1
  16. package/RangeSlider/index.js +14 -1
  17. package/Textarea/index.d.ts +2 -0
  18. package/Textarea/index.js +14 -1
  19. package/Tree/index.d.ts +1 -0
  20. package/Tree/index.js +29 -0
  21. package/Utils/useBoundedDrag.d.ts +125 -0
  22. package/Utils/useBoundedDrag.js +380 -0
  23. package/Utils/useDragDropPosition.d.ts +169 -0
  24. package/Utils/useDragDropPosition.js +456 -0
  25. package/Utils/useIsMobile.d.ts +2 -0
  26. package/Utils/useIsMobile.js +168 -0
  27. package/all.d.ts +1 -0
  28. package/all.js +1 -1
  29. package/lib/cjs/ColorPicker/index.js +3 -1
  30. package/lib/cjs/Date/index.d.ts +1 -0
  31. package/lib/cjs/Date/index.js +17 -2
  32. package/lib/cjs/DragDropList/index.d.ts +44 -0
  33. package/lib/cjs/DragDropList/index.js +1587 -0
  34. package/lib/cjs/Input/index.d.ts +2 -0
  35. package/lib/cjs/Input/index.js +14 -1
  36. package/lib/cjs/MasonryLayout/index.d.ts +2 -0
  37. package/lib/cjs/MasonryLayout/index.js +115 -5
  38. package/lib/cjs/MultipleSelect/index.d.ts +24 -10
  39. package/lib/cjs/MultipleSelect/index.js +2240 -1225
  40. package/lib/cjs/RangeSlider/index.js +14 -1
  41. package/lib/cjs/Textarea/index.d.ts +2 -0
  42. package/lib/cjs/Textarea/index.js +14 -1
  43. package/lib/cjs/Tree/index.d.ts +1 -0
  44. package/lib/cjs/Tree/index.js +29 -0
  45. package/lib/cjs/Utils/useBoundedDrag.d.ts +125 -0
  46. package/lib/cjs/Utils/useBoundedDrag.js +380 -0
  47. package/lib/cjs/Utils/useDragDropPosition.d.ts +169 -0
  48. package/lib/cjs/Utils/useDragDropPosition.js +456 -0
  49. package/lib/cjs/Utils/useIsMobile.d.ts +2 -0
  50. package/lib/cjs/Utils/useIsMobile.js +168 -0
  51. package/lib/cjs/index.d.ts +1 -0
  52. package/lib/cjs/index.js +1 -1
  53. package/lib/css/DragDropList/index.css +188 -0
  54. package/lib/css/MultipleSelect/index.css +237 -144
  55. package/lib/esm/ColorPicker/index.tsx +53 -49
  56. package/lib/esm/Date/index.tsx +3 -0
  57. package/lib/esm/DragDropList/index.scss +245 -0
  58. package/lib/esm/DragDropList/index.tsx +494 -0
  59. package/lib/esm/Input/index.tsx +17 -3
  60. package/lib/esm/MasonryLayout/index.tsx +125 -7
  61. package/lib/esm/MultipleSelect/index.scss +288 -183
  62. package/lib/esm/MultipleSelect/index.tsx +305 -166
  63. package/lib/esm/MultipleSelect/utils/func.ts +21 -1
  64. package/lib/esm/Tabs/Tabs.tsx +1 -1
  65. package/lib/esm/Textarea/index.tsx +18 -1
  66. package/lib/esm/Tree/TreeList.tsx +32 -0
  67. package/lib/esm/Tree/index.tsx +3 -0
  68. package/lib/esm/Utils/hooks/useBoundedDrag.tsx +301 -0
  69. package/lib/esm/Utils/hooks/useDragDropPosition.tsx +420 -0
  70. package/lib/esm/Utils/hooks/useIsMobile.tsx +56 -0
  71. package/lib/esm/index.js +1 -0
  72. package/package.json +1 -1
  73. package/lib/esm/MultipleSelect/ItemList.tsx +0 -323
@@ -0,0 +1,494 @@
1
+ import React, { useState, useRef, useEffect, forwardRef } from 'react';
2
+
3
+ import {
4
+ convertTree,
5
+ addTreeDepth,
6
+ } from 'funda-utils/dist/cjs/tree';
7
+ import { clsWrite, combinedCls } from 'funda-utils/dist/cjs/cls';
8
+ import useBoundedDrag from 'funda-utils/dist/cjs/useBoundedDrag';
9
+
10
+
11
+ export interface ListItem {
12
+ id: number;
13
+ parentId?: number;
14
+ label: string;
15
+ listItemLabel: string;
16
+ value: string;
17
+ queryString: string;
18
+ depth?: number;
19
+ children?: ListItem[];
20
+ disabled?: boolean;
21
+ appendControl?: React.ReactNode;
22
+ [key: string]: any;
23
+ }
24
+
25
+
26
+ export interface DragDropListProps {
27
+ wrapperClassName?: string;
28
+ prefix?: string;
29
+ data?: ListItem[];
30
+ draggable?: boolean;
31
+ handleHide?: boolean;
32
+ handleIcon?: string;
33
+ handlePos?: 'left' | 'right';
34
+ dragMode?: 'handle' | 'block';
35
+ editable?: boolean;
36
+ itemStyle?: React.CSSProperties;
37
+ hierarchical?: boolean;
38
+ indentation?: string;
39
+ doubleIndent?: boolean;
40
+ alternateCollapse?: boolean;
41
+ arrow?: React.ReactNode;
42
+ onUpdate?: (items: ListItem[], curId: number) => void;
43
+ }
44
+
45
+ export interface EditValue {
46
+ [propName: string]: string | number;
47
+ }
48
+
49
+ export interface TouchOffset {
50
+ x: number;
51
+ y: number;
52
+ }
53
+ export interface OptionConfig {
54
+ [propName: string]: string | number | boolean | Function | any[];
55
+ }
56
+
57
+ const DragDropList = forwardRef((props: DragDropListProps, externalRef: any) => {
58
+ const {
59
+ wrapperClassName,
60
+ prefix = 'custom',
61
+ data,
62
+ draggable = true,
63
+ handleHide = false,
64
+ handleIcon = '☰',
65
+ handlePos = 'left',
66
+ dragMode = 'handle',
67
+ editable = false,
68
+ itemStyle,
69
+ hierarchical = true,
70
+ indentation,
71
+ doubleIndent,
72
+ alternateCollapse,
73
+ arrow = <><svg viewBox="0 0 22 22" width="8px"><path d="m345.44 248.29l-194.29 194.28c-12.359 12.365-32.397 12.365-44.75 0-12.354-12.354-12.354-32.391 0-44.744l171.91-171.91-171.91-171.9c-12.354-12.359-12.354-32.394 0-44.748 12.354-12.359 32.391-12.359 44.75 0l194.29 194.28c6.177 6.18 9.262 14.271 9.262 22.366 0 8.099-3.091 16.196-9.267 22.373" transform="matrix(.03541-.00013.00013.03541 2.98 3.02)" fill="#a5a5a5" /></svg></>,
74
+ onUpdate,
75
+ ...attributes
76
+ } = props;
77
+
78
+
79
+ const INDENT_PLACEHOLDER = doubleIndent ? `&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;` : `&nbsp;&nbsp;&nbsp;&nbsp;`;
80
+ const INDENT_LAST_PLACEHOLDER = `${typeof indentation !== 'undefined' && indentation !== '' ? `${indentation}&nbsp;&nbsp;` : ''}`;
81
+
82
+ const rootRef = useRef<any>(null);
83
+ const [items, setItems] = useState<ListItem[]>([]);
84
+ const [editingItem, setEditingItem] = useState<number | null>(null);
85
+
86
+ const dragHandle = useRef<HTMLSpanElement | null>(null);
87
+
88
+
89
+ // Edit
90
+ const [editValue, setEditValue] = useState<Record<string, string | number>>({});
91
+
92
+ // Collapse/Expand
93
+ const [collapsedItems, setCollapsedItems] = useState<Set<number>>(new Set());
94
+
95
+
96
+ // Get editable field list
97
+ const getEditableFields = (item: ListItem): string[] => {
98
+ // Exclude fields that don't need to be edited
99
+ const excludeFields = ['id', 'parentId', 'depth', 'children', 'disabled', 'appendControl', 'parentItem'];
100
+ return Object.keys(item).filter(key => !excludeFields.includes(key));
101
+ };
102
+
103
+
104
+ // ================================================================
105
+ // General
106
+ // ================================================================
107
+ const deepCloneWithReactNode = (obj: any): any => {
108
+ if (obj === null || typeof obj !== 'object') {
109
+ return obj;
110
+ }
111
+
112
+ // Handle array
113
+ if (Array.isArray(obj)) {
114
+ return obj.map(item => deepCloneWithReactNode(item));
115
+ }
116
+
117
+ // Handle object
118
+ const clonedObj: any = {};
119
+ for (const key in obj) {
120
+ if (key === 'appendControl') {
121
+ clonedObj[key] = obj[key];
122
+ } else {
123
+ clonedObj[key] = deepCloneWithReactNode(obj[key]);
124
+ }
125
+ }
126
+ return clonedObj;
127
+ };
128
+
129
+
130
+ const getItemWithChildrenIndices = (items: ListItem[], startIndex: number): number[] => {
131
+ const indices = [startIndex];
132
+ const startItem = items[startIndex];
133
+ const startDepth = startItem.depth || 0;
134
+
135
+ // Check if subsequent items are child items
136
+ for (let i = startIndex + 1; i < items.length; i++) {
137
+ const currentItem = items[i];
138
+ const currentDepth = currentItem.depth || 0;
139
+ if (currentDepth > startDepth) {
140
+ indices.push(i);
141
+ } else {
142
+ break;
143
+ }
144
+ }
145
+
146
+ return indices;
147
+ };
148
+
149
+
150
+ const getIndentStr = (item: ListItem): number | string => {
151
+
152
+ // Add indent placeholder
153
+ let indent = '';
154
+ const depthData = item.depth;
155
+ if (depthData) {
156
+ Array(depthData).fill(0).forEach((k, i) => {
157
+ indent += INDENT_PLACEHOLDER;
158
+ if (i === depthData - 1) {
159
+ indent += INDENT_LAST_PLACEHOLDER;
160
+ }
161
+ });
162
+ }
163
+
164
+ return indent;
165
+ };
166
+
167
+
168
+
169
+ // ================================================================
170
+ // Collapse/Expand
171
+ // ================================================================
172
+ // Add collapse/expand handler function
173
+ const handleCollapse = (itemId: number, e: React.MouseEvent) => {
174
+ e.preventDefault();
175
+ e.stopPropagation();
176
+
177
+ setCollapsedItems(prev => {
178
+ const newCollapsed = new Set(prev);
179
+ if (newCollapsed.has(itemId)) {
180
+ newCollapsed.delete(itemId);
181
+ } else {
182
+ newCollapsed.add(itemId);
183
+ }
184
+ return newCollapsed;
185
+ });
186
+ };
187
+
188
+ // Helper function to determine if an item should be displayed
189
+ const shouldShowItem = (item: ListItem): boolean => {
190
+ if (!alternateCollapse) return true;
191
+
192
+ let currentId = item.parentId;
193
+ while (currentId) {
194
+ if (collapsedItems.has(currentId)) {
195
+ return false;
196
+ }
197
+ const parentItem = items.find(i => i.id === currentId);
198
+ currentId = parentItem?.parentId;
199
+ }
200
+ return true;
201
+ };
202
+
203
+ const hasChildren = (itemId: number): boolean => {
204
+ return items.some(item => item.parentId === itemId);
205
+ };
206
+
207
+
208
+
209
+
210
+ // ================================================================
211
+ // Drag & Drop Handlers (Desktop & Touch)
212
+ // ================================================================
213
+ const { isDragging, dragHandlers } = useBoundedDrag({
214
+ dragMode,
215
+ boundarySelector: `.${prefix}-draggable-list`,
216
+ itemSelector: `.${prefix}-draggable-list__item`,
217
+ dragHandleSelector: `.${prefix}-draggable-list__handle`,
218
+ onDragStart: (index: number) => {
219
+ // Additional drag start logic if needed
220
+ },
221
+ onDragOver: (dragIndex: number | null, dropIndex: number | null) => {
222
+ // Additional drag over logic if needed
223
+ },
224
+ onDragEnd: (dragIndex: number | null, dropIndex: number | null) => {
225
+ if (dragIndex !== null && dropIndex !== null && dragIndex !== dropIndex) {
226
+ // Handle item movement
227
+ const newItems = deepCloneWithReactNode(items);
228
+ const itemsToMove = getItemWithChildrenIndices(newItems, dragIndex);
229
+ const itemsBeingMoved = itemsToMove.map(index => newItems[index]);
230
+
231
+ // ... rest of your existing drag end logic ...
232
+
233
+ const _targetId = newItems[dragIndex]?.id;
234
+
235
+ // Calculate depth difference
236
+ const draggedDepth = newItems[dragIndex]?.depth || 0;
237
+ const dropDepth = newItems[dropIndex]?.depth || 0;
238
+ const depthDiff = dropDepth - draggedDepth;
239
+
240
+ // Adjust depth for all moving items
241
+ itemsBeingMoved.forEach(item => {
242
+ if (item.depth !== undefined) {
243
+ item.depth += depthDiff;
244
+ }
245
+ });
246
+
247
+ // Remove all items from their original location (from back to front to keep indexing correct)
248
+ itemsToMove.reverse().forEach(index => {
249
+ newItems.splice(index, 1);
250
+ });
251
+
252
+ // Calculate new insert position
253
+ let insertIndex = dropIndex;
254
+ if (dropIndex > dragIndex) {
255
+ insertIndex -= itemsToMove.length;
256
+ }
257
+
258
+ // Insert all items
259
+ newItems.splice(insertIndex, 0, ...itemsBeingMoved);
260
+
261
+ // Rebuild tree structure
262
+ const tree = hierarchical ? convertTree(newItems, '', 'id', 'parentId') : newItems;
263
+ const updatedItems = hierarchical ? addTreeDepth(tree) : tree;
264
+
265
+ setItems(updatedItems);
266
+ onUpdate?.(updatedItems, _targetId);
267
+ }
268
+ }
269
+ });
270
+
271
+
272
+
273
+ // ================================================================
274
+ // Editable
275
+ // ================================================================
276
+
277
+ const handleDoubleClick = (item: ListItem) => {
278
+ if (!editable) return;
279
+
280
+ setEditingItem(item.id);
281
+ // Only editable fields are copied
282
+ const editableFields = getEditableFields(item);
283
+ const editableValues = editableFields.reduce((acc, field) => ({
284
+ ...acc,
285
+ [field]: item[field as keyof ListItem]
286
+ }), {});
287
+
288
+ setEditValue(editableValues);
289
+ };
290
+
291
+ const handleEditCancel = () => {
292
+ setEditingItem(null);
293
+ setEditValue({});
294
+ };
295
+
296
+ const handleEditSave = (itemId: number) => {
297
+ const newItems: ListItem[] = items.map(item => {
298
+ if (item.id === itemId) {
299
+ return {
300
+ ...item,
301
+ ...editValue
302
+ };
303
+ }
304
+ return item;
305
+ });
306
+
307
+ setItems(newItems);
308
+ onUpdate?.(newItems, itemId);
309
+ setEditingItem(null);
310
+ setEditValue({});
311
+ };
312
+
313
+ const handleInputChange = (field: string, value: any) => {
314
+ setEditValue(prev => ({
315
+ ...prev,
316
+ [field]: value
317
+ }));
318
+ };
319
+
320
+
321
+ const handleKeyDown = (e: any, itemId: number) => {
322
+ if (e.key === 'Enter') {
323
+ handleEditSave(itemId);
324
+ } else if (e.key === 'Escape') {
325
+ handleEditCancel();
326
+ }
327
+ };
328
+
329
+
330
+
331
+ const renderEditForm = (item: ListItem) => {
332
+ const editableFields = getEditableFields(item);
333
+
334
+ return (
335
+ <div className={`${prefix}-draggable-list__edit-form`}>
336
+ {editableFields.map((field) => (
337
+ <div key={field} className={`${prefix}-draggable-list__edit-field`}>
338
+ <label>{field}:</label>
339
+ <input
340
+ type="text"
341
+ value={editValue[field] || ''}
342
+ onChange={(e) => handleInputChange(field, e.target.value)}
343
+ onKeyDown={(e) => handleKeyDown(e, item.id)}
344
+ placeholder={field}
345
+ autoFocus={field === editableFields[0]}
346
+ />
347
+ </div>
348
+ ))}
349
+
350
+ <div className={`${prefix}-draggable-list__edit-buttons`}>
351
+ <button onClick={() => handleEditSave(item.id)}>✓</button>
352
+ <button onClick={handleEditCancel}>✕</button>
353
+ </div>
354
+ </div>
355
+ );
356
+ };
357
+
358
+ useEffect(() => {
359
+
360
+ // data init
361
+ //--------------
362
+ if (typeof data !== 'undefined' && Array.isArray(data)) {
363
+ const tree = hierarchical ? convertTree(data, '', 'id', 'parentId') : data;
364
+ const _ORGIN_DATA = hierarchical ? addTreeDepth(tree) : tree;
365
+ setItems(_ORGIN_DATA);
366
+ }
367
+ }, [data]);
368
+
369
+
370
+
371
+ return (
372
+ <ul
373
+ {...attributes}
374
+ ref={(node) => {
375
+ rootRef.current = node;
376
+ if (typeof externalRef === 'function') {
377
+ externalRef(node);
378
+ } else if (externalRef) {
379
+ externalRef.current = node;
380
+ }
381
+ }}
382
+ className={combinedCls(
383
+ `${prefix}-draggable-list`,
384
+ clsWrite(wrapperClassName, 'mb-3'),
385
+ clsWrite(dragMode, 'handle'),
386
+ `handle-pos-${handlePos ?? 'left'}`,
387
+ {
388
+ 'draggable': draggable,
389
+ 'icon-hide': handleHide,
390
+ 'alternate-collapse': alternateCollapse
391
+ }
392
+ )}
393
+ >
394
+ {items.map((item: ListItem, index: number) => {
395
+
396
+ // If the item should be hidden, the rendering is skipped
397
+ if (!shouldShowItem(item)) return null;
398
+
399
+ // collapse
400
+ const hasChildItems = hasChildren(item.id);
401
+ const isCollapsed = collapsedItems.has(item.id);
402
+
403
+
404
+ return <li
405
+ key={item.id}
406
+ data-index={index}
407
+ data-id={item.id}
408
+ data-parent-id={item.parentId}
409
+ data-value={item.value}
410
+ data-label={item.label}
411
+ data-listitemlabel={item.listItemLabel}
412
+ className={combinedCls(
413
+ `${prefix}-draggable-list__item`,
414
+ clsWrite(dragMode, 'handle'),
415
+ {
416
+ 'disabled': item.disabled,
417
+ 'draggable': draggable,
418
+ 'editing': editingItem === item.id,
419
+
420
+ // collapse
421
+ 'has-children': hasChildItems,
422
+ 'collapsed': isCollapsed
423
+ }
424
+ )}
425
+ draggable={!draggable ? undefined : editingItem !== item.id && "true"}
426
+ onDragStart={!draggable ? undefined : (e) => dragHandlers.handleDragStart(e, index)}
427
+ onDragOver={!draggable ? undefined : dragHandlers.handleDragOver}
428
+ onDragEnd={!draggable ? undefined : dragHandlers.handleDragEnd}
429
+ onTouchStart={!draggable ? undefined : (e) => dragHandlers.handleDragStart(e, index)}
430
+ onTouchMove={!draggable ? undefined : dragHandlers.handleDragOver}
431
+ onTouchEnd={!draggable ? undefined : dragHandlers.handleDragEnd}
432
+ style={itemStyle}
433
+ onDoubleClick={() => handleDoubleClick(item)}
434
+ >
435
+ <div className={`${prefix}-draggable-list__itemcontent`}>
436
+
437
+ {/** DRAG HANDLE */}
438
+ {/* Fix the problem that mobile terminals cannot be touched, DO NOT USE "<svg>" */}
439
+ {draggable && !handleHide ? <span ref={dragHandle} className={`${prefix}-draggable-list__handle ${handlePos ?? 'left'}`} draggable={dragMode === 'handle'} dangerouslySetInnerHTML={{
440
+ __html: `${handleIcon}`
441
+ }}></span> : null}
442
+ {/** /DRAG HANDLE */}
443
+
444
+ {editingItem === item.id ? (
445
+ renderEditForm(item)
446
+ ) : (
447
+ <div className={`${prefix}-draggable-list__itemcontent-inner`}>
448
+
449
+ <div className={`${prefix}-draggable-list__itemlabel`}>
450
+
451
+
452
+ {/** LABEL */}
453
+
454
+ <span dangerouslySetInnerHTML={{
455
+ __html: `${getIndentStr(item)}${typeof item.listItemLabel === 'undefined' ? item.label : item.listItemLabel}`
456
+ }} />
457
+ {/** /LABEL */}
458
+
459
+
460
+
461
+
462
+ {/** COLLOPSE */}
463
+ {alternateCollapse && hasChildItems && (
464
+ <span
465
+ className={`${prefix}-draggable-list__collapse-arrow`}
466
+ onClick={(e) => handleCollapse(item.id, e)}
467
+ >
468
+ {arrow || (isCollapsed ? '▶' : '▼')}
469
+ </span>
470
+ )}
471
+ {/** /COLLOPSE */}
472
+
473
+ </div>
474
+
475
+
476
+ {/** EXTENDS */}
477
+ {item.appendControl ? <>
478
+ <div className={`${prefix}-draggable-list__itemext`} id={`${prefix}-draggable-list__itemext-${item.value}`}>
479
+ {item.appendControl}
480
+ </div>
481
+ </> : null}
482
+ {/** /EXTENDS */}
483
+
484
+ </div>
485
+ )}
486
+ </div>
487
+ </li>
488
+ })}
489
+ </ul>
490
+ );
491
+ });
492
+
493
+
494
+ export default DragDropList;
@@ -6,8 +6,6 @@ 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
-
10
-
11
9
  export type InputProps = {
12
10
  contentRef?: React.ForwardedRef<any>;
13
11
  wrapperClassName?: string;
@@ -61,6 +59,8 @@ export type InputProps = {
61
59
  onBlur?: (e: any, param: any, el: any) => void;
62
60
  onFocus?: (e: any, param: any, el: any) => void;
63
61
  onPressEnter?: (e: any, el: any) => void;
62
+ onKeyDown?: (e: any, el: any) => void;
63
+ onKeyUp?: (e: any, el: any) => void;
64
64
 
65
65
  };
66
66
 
@@ -117,6 +117,8 @@ const Input = forwardRef((props: InputProps, externalRef: any) => {
117
117
  onBlur,
118
118
  onFocus,
119
119
  onPressEnter,
120
+ onKeyDown,
121
+ onKeyUp,
120
122
  ...attributes
121
123
  } = props;
122
124
 
@@ -312,7 +314,12 @@ const Input = forwardRef((props: InputProps, externalRef: any) => {
312
314
  set: (value: string, cb?: any) => {
313
315
  setChangedVal(`${value}`);
314
316
  cb?.();
315
- }
317
+ },
318
+ aiPredictReset: () => {
319
+ setTimeout(() => { // Avoid conflicts with other asynchronous states, resulting in invalid clearing
320
+ setCurrentSuggestion('');
321
+ }, 0);
322
+ },
316
323
  }),
317
324
  [contentRef],
318
325
  );
@@ -383,6 +390,9 @@ const Input = forwardRef((props: InputProps, externalRef: any) => {
383
390
 
384
391
 
385
392
  function handleKeyPressed(event: KeyboardEvent<HTMLInputElement>) {
393
+
394
+ onKeyDown?.(event, valRef.current);
395
+
386
396
  if (typeof (onKeyPressedCallback) === 'function') {
387
397
  const newData: any = onKeyPressedCallback(event, valRef.current);
388
398
  if (newData) setChangedVal(newData); // Avoid the error "react checkbox changing an uncontrolled input to be controlled"
@@ -440,6 +450,9 @@ const Input = forwardRef((props: InputProps, externalRef: any) => {
440
450
 
441
451
  }
442
452
 
453
+ function handleKeyUp(event: KeyboardEvent<HTMLInputElement>) {
454
+ onKeyUp?.(event, valRef.current);
455
+ }
443
456
 
444
457
  useEffect(() => {
445
458
 
@@ -544,6 +557,7 @@ const Input = forwardRef((props: InputProps, externalRef: any) => {
544
557
 
545
558
  }}
546
559
  onKeyDown={handleKeyPressed}
560
+ onKeyUp={handleKeyUp}
547
561
  onCompositionStart={handleComposition}
548
562
  onCompositionUpdate={handleComposition}
549
563
  onCompositionEnd={handleComposition}