@skalfa/skalfa-app 1.0.3 → 1.0.6

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 (90) hide show
  1. package/.env.example +8 -16
  2. package/app/auth/edit/page.tsx +1 -1
  3. package/app/auth/login/page.tsx +1 -1
  4. package/app/auth/me/page.tsx +1 -1
  5. package/app/auth/register/page.tsx +1 -1
  6. package/app/auth/verify/page.tsx +1 -1
  7. package/app/dashboard/layout.tsx +2 -2
  8. package/app/dashboard/page.tsx +1 -1
  9. package/app/index.ts +1 -0
  10. package/app/layout.tsx +2 -4
  11. package/app/page.tsx +2 -2
  12. package/bun.lock +7 -2
  13. package/components/index.ts +1 -3
  14. package/package.json +10 -7
  15. package/styles/components.css +1392 -0
  16. package/styles/globals.css +40 -175
  17. package/styles/utilities.css +37 -0
  18. package/tsconfig.json +4 -2
  19. package/utils/commands/skalfa.ts +1 -1
  20. package/components/base.components/accordion/Accordion.component.tsx +0 -82
  21. package/components/base.components/breadcrumb/Breadcrumb.component.tsx +0 -80
  22. package/components/base.components/button/Button.component.tsx +0 -91
  23. package/components/base.components/button/IconButton.component.tsx +0 -88
  24. package/components/base.components/button/button.decorate.ts +0 -82
  25. package/components/base.components/card/AlertCard.component.tsx +0 -69
  26. package/components/base.components/card/Card.component.tsx +0 -25
  27. package/components/base.components/card/DashboardCard.component.tsx +0 -44
  28. package/components/base.components/card/GalleryCard.component.tsx +0 -50
  29. package/components/base.components/card/ProductCard.component.tsx +0 -65
  30. package/components/base.components/card/ProfileCard.component.tsx +0 -71
  31. package/components/base.components/carousel/Carousel.component.tsx +0 -113
  32. package/components/base.components/chip/Chip.component.tsx +0 -39
  33. package/components/base.components/document/DocumentViewer.component.tsx +0 -164
  34. package/components/base.components/document/ExportExcel.component.tsx +0 -340
  35. package/components/base.components/document/ImportExcel.component.tsx +0 -315
  36. package/components/base.components/document/PrintTable.component.tsx +0 -204
  37. package/components/base.components/document/RenderPDF.component.tsx +0 -416
  38. package/components/base.components/index.ts +0 -85
  39. package/components/base.components/input/Checkbox.component.tsx +0 -109
  40. package/components/base.components/input/Input.component.tsx +0 -332
  41. package/components/base.components/input/InputCheckbox.component.tsx +0 -174
  42. package/components/base.components/input/InputCurrency.component.tsx +0 -163
  43. package/components/base.components/input/InputDate.component.tsx +0 -352
  44. package/components/base.components/input/InputDatetime.component.tsx +0 -260
  45. package/components/base.components/input/InputDocument.component.tsx +0 -352
  46. package/components/base.components/input/InputImage.component.tsx +0 -533
  47. package/components/base.components/input/InputMap.component.tsx +0 -318
  48. package/components/base.components/input/InputNumber.component.tsx +0 -192
  49. package/components/base.components/input/InputOtp.component.tsx +0 -169
  50. package/components/base.components/input/InputPassword.component.tsx +0 -236
  51. package/components/base.components/input/InputRadio.component.tsx +0 -175
  52. package/components/base.components/input/InputTime.component.tsx +0 -276
  53. package/components/base.components/input/InputValues.component.tsx +0 -68
  54. package/components/base.components/input/Radio.component.tsx +0 -102
  55. package/components/base.components/input/Select.component.tsx +0 -541
  56. package/components/base.components/modal/BottomSheet.component.tsx +0 -246
  57. package/components/base.components/modal/FloatingPage.component.tsx +0 -104
  58. package/components/base.components/modal/Modal.component.tsx +0 -96
  59. package/components/base.components/modal/ModalConfirm.component.tsx +0 -218
  60. package/components/base.components/modal/Toast.component.tsx +0 -126
  61. package/components/base.components/nav/Bottombar.component.tsx +0 -116
  62. package/components/base.components/nav/Footer.component.tsx +0 -144
  63. package/components/base.components/nav/Headbar.component.tsx +0 -104
  64. package/components/base.components/nav/Navbar.component.tsx +0 -100
  65. package/components/base.components/nav/Sidebar.component.tsx +0 -301
  66. package/components/base.components/nav/Tabbar.component.tsx +0 -60
  67. package/components/base.components/nav/Wizard.component.tsx +0 -73
  68. package/components/base.components/supervision/FormSupervision.component.tsx +0 -434
  69. package/components/base.components/supervision/TableSupervision.component.tsx +0 -697
  70. package/components/base.components/table/ControlBar.component.tsx +0 -497
  71. package/components/base.components/table/FilterComponent.tsx +0 -518
  72. package/components/base.components/table/Pagination.component.tsx +0 -159
  73. package/components/base.components/table/Table.component.tsx +0 -469
  74. package/components/base.components/typography/TypographyArticle.component.tsx +0 -26
  75. package/components/base.components/typography/TypographyColumn.component.tsx +0 -20
  76. package/components/base.components/typography/TypographyContent.component.tsx +0 -20
  77. package/components/base.components/typography/TypographyTips.component.tsx +0 -20
  78. package/components/base.components/wrap/Draggable.component.tsx +0 -303
  79. package/components/base.components/wrap/IDBProvider.tsx +0 -12
  80. package/components/base.components/wrap/Image.component.tsx +0 -10
  81. package/components/base.components/wrap/OutsideClick.component.tsx +0 -48
  82. package/components/base.components/wrap/ScrollContainer.component.tsx +0 -104
  83. package/components/base.components/wrap/ShortcutProvider.tsx +0 -57
  84. package/components/base.components/wrap/Swipe.component.tsx +0 -93
  85. package/components/construct.components/example.tsx +0 -1
  86. package/components/construct.components/index.ts +0 -5
  87. package/components/structure.components/example.tsx +0 -1
  88. package/components/structure.components/index.ts +0 -5
  89. package/schema/idb/app.schema.ts +0 -9
  90. package/schema/index.ts +0 -5
@@ -1,541 +0,0 @@
1
- "use client"
2
-
3
- import { ReactNode, useEffect, useState } from "react";
4
- import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
5
- import { faCheck, faChevronDown, faTimes,} from "@fortawesome/free-solid-svg-icons";
6
- import { api, ApiType, cavity, cn, pcn, registry, useInputHandler, useInputRandomId, useLazySearch, useValidation, validation, ValidationRules,} from "@utils";
7
-
8
-
9
-
10
- type CT = "label" | "tip" | "error" | "input" | "icon" | "suggest" | "suggest-item";
11
-
12
- export interface SelectOptionProps {
13
- label : string | ReactNode;
14
- value : string | number;
15
- searchable ?: string[];
16
- customLabel ?: ReactNode;
17
- };
18
-
19
- export interface SelectProps {
20
- name : string;
21
- label ?: string;
22
- placeholder ?: string;
23
- tip ?: string | ReactNode;
24
- leftIcon ?: any;
25
- rightIcon ?: any;
26
-
27
- value ?: string | number | (string | number)[];
28
- invalid ?: string;
29
- disabled ?: boolean;
30
- validations ?: ValidationRules;
31
- multiple ?: boolean;
32
- autoFocus ?: boolean;
33
- clearable ?: boolean;
34
-
35
- options ?: SelectOptionProps[];
36
- searchable ?: boolean;
37
- serverOptionControl ?: ApiType & { cacheName?: string | false };
38
- idbOptionControl ?: { store: string, labelKey: string, valueKey: string };
39
- serverSearchable ?: boolean;
40
- includedOptions ?: SelectOptionProps[];
41
- exceptOptions ?: (string | number)[];
42
- tempOptions ?: SelectOptionProps[];
43
- newOption ?: SelectOptionProps;
44
- maxShowOption ?: number;
45
-
46
- onChange ?: (value: string | number | (string | number)[], data?: any) => any;
47
- register ?: (name: string, validations?: ValidationRules) => void;
48
- unregister ?: (name: string) => void;
49
- onFocus ?: () => void;
50
- onBlur ?: () => void;
51
-
52
- /** Use custom class with: "label::", "tip::", "error::", "icon::", "suggest::", "suggest-item::". */
53
- className ?: string;
54
- }
55
-
56
-
57
-
58
- export function SelectComponent({
59
- name,
60
- label,
61
- placeholder,
62
- tip,
63
- leftIcon,
64
- rightIcon,
65
-
66
- value,
67
- invalid,
68
- disabled,
69
- validations,
70
- multiple,
71
- autoFocus,
72
- clearable,
73
-
74
- options = [],
75
- searchable,
76
- serverOptionControl,
77
- idbOptionControl,
78
- serverSearchable,
79
- includedOptions = [],
80
- exceptOptions = [],
81
- tempOptions,
82
- newOption,
83
- maxShowOption = 10,
84
-
85
- register,
86
- unregister,
87
- onChange,
88
- onFocus,
89
- onBlur,
90
-
91
- className = "",
92
- }: SelectProps) {
93
- const [inputShowValue, setInputShowValue] = useState<string | ReactNode>("");
94
- const [keydown, setKeydown] = useState(false);
95
- const [useTemp, setUseTemp] = useState(true);
96
- const [dataOptions, setDataOptions] = useState<SelectOptionProps[]>([]);
97
- const [filteredOptions, setFilteredOptions] = useState<SelectOptionProps[]>([]);
98
- const [loadingOption, setLoadingOption] = useState(false);
99
- const [activeOption, setActiveOption] = useState(0);
100
- const [showOption, setShowOption] = useState(false);
101
- const [keyword, setKeyword] = useState("");
102
- const [keywordSearch] = useLazySearch(keyword);
103
-
104
-
105
- // =========================>
106
- // ## Initial
107
- // =========================>
108
- const inputHandler = useInputHandler(name, value, validations, register, unregister, false)
109
- const randomId = useInputRandomId()
110
-
111
-
112
- // =========================>
113
- // ## Invalid handler
114
- // =========================>
115
- const [invalidMessage] = useValidation(inputHandler.value, validations, invalid, inputHandler.idle);
116
-
117
-
118
- // =========================>
119
- // ## change value handler
120
- // =========================>
121
- useEffect(() => {
122
- if (value) {
123
- inputHandler.setValue(value);
124
- Array.isArray(dataOptions) && setInputShowValue((newOption ? [newOption, ...dataOptions] : dataOptions)?.find((option) => option.value == value)?.label || "");
125
- inputHandler.setIdle(false);
126
- } else {
127
- inputHandler.setValue("");
128
- setInputShowValue("");
129
- }
130
- }, [value, dataOptions]);
131
-
132
-
133
- // =========================>
134
- // ## options handler
135
- // =========================>
136
- useEffect(() => {
137
- options?.length && setDataOptions([...options, ...includedOptions].filter((op: SelectOptionProps) => !exceptOptions?.includes(op.value)));
138
- }, [options]);
139
-
140
-
141
- const filterOption = (e: any) => {
142
- if (dataOptions?.length) {
143
- let newFilteredOptions: SelectOptionProps[] = [];
144
-
145
- if (searchable && !serverSearchable) {
146
- if (e.target.value) {
147
- newFilteredOptions = dataOptions.filter((Option) => (Option.label as string)?.toLowerCase().indexOf(e.target.value.toLowerCase()) > -1).slice(0, maxShowOption);
148
- } else {
149
- newFilteredOptions = dataOptions.slice(0, maxShowOption);
150
- }
151
- } else {
152
- newFilteredOptions = dataOptions;
153
- }
154
-
155
- setActiveOption(-1);
156
- setFilteredOptions(newFilteredOptions);
157
- setShowOption(true);
158
- }
159
- };
160
-
161
-
162
- const onKeyDownOption = (e: any) => {
163
- if (dataOptions?.length) {
164
- if (e.keyCode === 13) {
165
- const resultValue = filteredOptions?.at(activeOption);
166
- setActiveOption(-1);
167
- setFilteredOptions([]);
168
- setShowOption(false);
169
- if (!multiple) {
170
- setInputShowValue(resultValue?.label || inputShowValue);
171
- inputHandler.setValue(resultValue?.value || inputShowValue);
172
- serverSearchable && setKeyword((resultValue?.label as string) || keyword);
173
- } else {
174
- if (resultValue?.value) {
175
- searchable ? setInputShowValue(resultValue.label) : searchable && setInputShowValue("");
176
- serverSearchable && setKeyword(resultValue.label as string);
177
-
178
- const values: string[] = Array.isArray(inputHandler.value) ? Array().concat(inputHandler.value)?.filter((val: string | number) => val != resultValue?.value) : [];
179
-
180
- if (values.find((val) => val == resultValue?.value)) {
181
- inputHandler.setValue(values);
182
- } else {
183
- inputHandler.setValue([...Array().concat(values), resultValue.value]);
184
- }
185
- }
186
- }
187
- e.preventDefault();
188
- } else if (e.keyCode === 38) {
189
- if (activeOption === 0) return;
190
- setActiveOption(activeOption - 1);
191
- } else if (e.keyCode === 40) {
192
- if (activeOption + 1 >= (filteredOptions?.length || 0)) return;
193
- setActiveOption(activeOption + 1);
194
- }
195
- }
196
- };
197
-
198
- const fetchOptions = async () => {
199
- setLoadingOption(true);
200
-
201
- const serverControl = {
202
- ...serverOptionControl,
203
- params: serverSearchable ? { search: keywordSearch, ...(serverOptionControl?.params || {}) } : (serverOptionControl?.params || {}),
204
- headers: { "X-Option": 1 }
205
- };
206
-
207
- const getCacheOptions = await cavity.get(serverOptionControl?.cacheName || `option_${serverOptionControl?.path}`)
208
- const cacheOptions = (getCacheOptions?.data || []) as SelectOptionProps[];
209
-
210
- if (cacheOptions?.length) {
211
- setDataOptions(
212
- [...cacheOptions, ...includedOptions].filter(
213
- (op: SelectOptionProps) => !exceptOptions?.includes(op.value)
214
- )
215
- );
216
- setLoadingOption(false);
217
- } else {
218
- const mutateOptions = await api(serverControl || {});
219
- setDataOptions(
220
- [...(mutateOptions?.data?.data || []), ...(includedOptions || [])].filter(
221
- (op: SelectOptionProps) => !exceptOptions?.includes(op.value)
222
- )
223
- );
224
- setShowOption(true);
225
-
226
- if(serverOptionControl?.cacheName != false) {
227
- cavity.set({
228
- key: serverOptionControl?.cacheName || `option_${serverOptionControl?.path}`,
229
- data: mutateOptions?.data,
230
- expired: 5,
231
- });
232
- }
233
- setLoadingOption(false);
234
- }
235
- };
236
-
237
- const fetchIdbOptions = async () => {
238
- setLoadingOption(true);
239
-
240
- if (idbOptionControl?.store) {
241
- const idb = registry.get("idb");
242
- if (!idb) {
243
- throw new Error("IndexedDB (IDB) extension is not installed.");
244
- }
245
- const getIdbOptions = await (await idb.query(idbOptionControl?.store)).get()
246
-
247
- const rows = getIdbOptions.map((row: Record<string,any>) => {
248
- const value = row[idbOptionControl.valueKey] || row["id"];
249
- const label = row[idbOptionControl.labelKey] || row["id"];
250
-
251
- return {
252
- label,
253
- value,
254
- ...row,
255
- }
256
- })
257
-
258
- setDataOptions(rows);
259
- setLoadingOption(false);
260
- }
261
- };
262
-
263
- useEffect(() => {
264
- if (!serverSearchable) {
265
- if (serverOptionControl?.path || serverOptionControl?.url) {
266
- fetchOptions();
267
- } else if (idbOptionControl?.store) {
268
- fetchIdbOptions();
269
- } else {
270
- !options && setDataOptions([]);
271
- }
272
- }
273
-
274
- }, [serverOptionControl?.path, serverOptionControl?.url]);
275
-
276
- useEffect(() => {
277
- if (serverSearchable) {
278
- if (serverOptionControl?.path || serverOptionControl?.url) {
279
- fetchOptions();
280
- } else {
281
- !options && setDataOptions([]);
282
- }
283
- }
284
- }, [keywordSearch, serverOptionControl?.path, serverOptionControl?.url]);
285
-
286
- return (
287
- <>
288
- <div className="relative flex flex-col gap-y-0.5">
289
- <label
290
- htmlFor={randomId}
291
- className={cn(
292
- "input-label",
293
- pcn<CT>(className, "label"),
294
- disabled && "opacity-50",
295
- disabled && pcn<CT>(className, "label", "disabled"),
296
- inputHandler.focus && "text-primary",
297
- inputHandler.focus && pcn<CT>(className, "label", "focus"),
298
- invalidMessage && "text-danger",
299
- invalidMessage && pcn<CT>(className, "label", "focus")
300
- )}
301
- >
302
- {label}
303
- {validations && validation.hasRules(validations, "required") && <span className="text-danger ml-1">*</span>}
304
- </label>
305
-
306
- {tip && (
307
- <small
308
- className={cn(
309
- "input-tip",
310
- pcn<CT>(className, "tip"),
311
- disabled && "opacity-60",
312
- disabled && pcn<CT>(className, "tip", "disabled")
313
- )}
314
- >{tip}</small>
315
- )}
316
-
317
- <div className="relative">
318
- <input
319
- type="hidden"
320
- value={!multiple ? String(inputHandler.value) : Array().concat(inputHandler.value).map((val) => String(val))}
321
- name={name}
322
- />
323
- <input
324
- type="text"
325
- readOnly={!searchable}
326
- id={randomId}
327
- placeholder={!inputHandler.value || (Array.isArray(inputHandler.value) && !inputHandler.value.length) ? placeholder : ""}
328
- disabled={disabled}
329
- className={cn(
330
- "input cursor-pointer",
331
- leftIcon && "pl-12",
332
- rightIcon && "pr-12",
333
- pcn<CT>(className, "input"),
334
- invalidMessage && "input-error",
335
- invalidMessage && pcn<CT>(className, "input", "error")
336
- )}
337
- value={(useTemp && tempOptions ? tempOptions.at(0)?.label : serverSearchable ? keyword : inputShowValue) as string}
338
- onChange={(e) => {
339
- setUseTemp(false);
340
- searchable && setInputShowValue(e.target.value);
341
- serverSearchable && setKeyword(e.target.value);
342
- inputHandler.setIdle(false);
343
- dataOptions?.length && filterOption(e);
344
- }}
345
- onFocus={(e) => {
346
- setUseTemp(false);
347
- inputHandler.setFocus(true);
348
- onFocus?.();
349
- dataOptions?.length && filterOption(e);
350
- searchable && e.target.select();
351
- }}
352
- onBlur={(e) => {
353
- setUseTemp(false);
354
- const value = e.target.value;
355
- const valueOption = dataOptions?.find((option) => (option.label as string)?.toLowerCase() == value?.toLowerCase());
356
-
357
- if (!keydown) {
358
- if (!multiple) {
359
- setTimeout(() => {
360
- if (valueOption?.value) {
361
- setInputShowValue(valueOption.label);
362
- inputHandler.setValue(valueOption.value);
363
- serverSearchable && setKeyword(valueOption.label as string);
364
- onChange?.(valueOption.value, valueOption);
365
- } else {
366
- setInputShowValue("");
367
- serverSearchable && setKeyword("");
368
- inputHandler.setValue("");
369
- onChange?.("");
370
- }
371
- }, 140);
372
- } else {
373
- setInputShowValue("");
374
- serverSearchable && setKeyword("");
375
- onChange?.("");
376
- }
377
- }
378
-
379
- setTimeout(() => {
380
- inputHandler.setFocus(false);
381
- }, 100);
382
-
383
- onBlur?.();
384
- }}
385
- onKeyDown={(e) => {
386
- dataOptions?.length && onKeyDownOption(e);
387
- }}
388
- autoComplete="off"
389
- autoFocus={autoFocus}
390
- />
391
-
392
-
393
- {(multiple && !searchable || (searchable && !inputHandler.focus)) && (
394
- <div
395
- className={`absolute top-1/2 -translate-y-1/2 overflow-x-auto py-1.5 input-scroll ${leftIcon ? "ml-[2.5rem]" : "ml-2"}`}
396
- style={{ maxWidth: `calc(100% - ${leftIcon ? "5.2rem" : "3.2rem"})` }}
397
- >
398
- <div className={`input-values-container`}>
399
- {multiple && typeof inputHandler.value != "string" && Array().concat(inputHandler.value)?.map((item, key) => {
400
- return (
401
- <div key={key} className={`input-values-item`}>
402
- <span className="">{dataOptions?.find((option) => option.value == item)?.label}</span>
403
- <FontAwesomeIcon
404
- icon={faTimes}
405
- className={`input-values-delete`}
406
- onClick={() => {
407
- const values = Array().concat(inputHandler.value);
408
- const index = values.findIndex((val: string | number) => val == item);
409
-
410
- inputHandler.setValue(values.filter((_, val) => val != index));
411
-
412
- if (!values.filter((_, val) => val != index)?.length) {
413
- setInputShowValue("");
414
- serverSearchable && setKeyword("");
415
- onChange?.("");
416
- }
417
- }}
418
- />
419
- </div>
420
- );
421
- })}
422
- </div>
423
- </div>
424
- )}
425
-
426
-
427
- {leftIcon && (
428
- <FontAwesomeIcon
429
- className={cn(
430
- "left-4 input-icon ",
431
- pcn<CT>(className, "icon"),
432
- disabled && "opacity-60",
433
- disabled && pcn<CT>(className, "icon", "disabled"),
434
- inputHandler.focus && "text-primary",
435
- inputHandler.focus && pcn<CT>(className, "icon", "focus")
436
- )}
437
- icon={leftIcon}
438
- />
439
- )}
440
-
441
- {!multiple && clearable && inputHandler.value && (
442
- <div
443
- className={cn(
444
- "right-12 input-icon cursor-pointer hover:text-danger",
445
- disabled && "opacity-60 pointer-events-none",
446
- disabled && pcn<CT>(className, "icon", "disabled")
447
- )}
448
- onClick={() => {
449
- setInputShowValue("");
450
- inputHandler.setValue("");
451
- onChange?.("");
452
- }}
453
- >
454
- <FontAwesomeIcon icon={faTimes} />
455
- </div>
456
- )}
457
-
458
- <label
459
- htmlFor={randomId}
460
- className={cn(
461
- "right-4 input-icon cursor-pointer hover:text-primary",
462
- disabled && "opacity-60 pointer-events-none",
463
- disabled && pcn<CT>(className, "icon", "disabled")
464
- )}
465
- >
466
- <FontAwesomeIcon icon={faChevronDown} />
467
- </label>
468
- </div>
469
-
470
- {!!dataOptions?.length && showOption && !loadingOption && !!filteredOptions?.length && (
471
- <div>
472
- <ul className={`input-suggest-container scroll-sm ${inputHandler.focus ? "opacity-100 scale-y-100" : "opacity-0 scale-y-0"}`}>
473
- {(newOption ? [newOption, ...filteredOptions] : filteredOptions ).map((option, key) => {
474
- const selected = !!((typeof inputHandler.value == "string" || typeof inputHandler.value == "number") && inputHandler.value == option.value) ||
475
- (Array.isArray(inputHandler.value) && Array().concat(inputHandler.value).find((val: string | number) => val == option.value));
476
-
477
- return (
478
- <li
479
- className={`
480
- cursor-pointer hover:bg-light-primary
481
- input-suggest
482
- ${(key == activeOption || selected) && "bg-light-primary text-primary"}
483
- `}
484
- key={key}
485
- onMouseDown={() => {
486
- setKeydown(true);
487
- setTimeout(() => inputHandler.setFocus(true), 110);
488
- }}
489
- onMouseUp={() => {
490
- setKeydown(false);
491
- setActiveOption(key);
492
- setFilteredOptions([]);
493
- setShowOption(false);
494
-
495
- if (!multiple) {
496
- setInputShowValue(option.label);
497
- serverSearchable && setKeyword(option.label as string);
498
- inputHandler.setValue(option.value);
499
- onChange?.(option.value, option);
500
- } else {
501
- const values: string[] | number[] = Array.isArray(inputHandler.value)
502
- ? Array().concat(inputHandler.value).filter((val) => val != option.value)
503
- : [];
504
-
505
- setInputShowValue("");
506
- serverSearchable && setKeyword("");
507
-
508
- if (
509
- Array.isArray(inputHandler.value) && Array().concat(inputHandler.value).find((val) => val == option.value)
510
- ) {
511
- inputHandler.setValue(values);
512
- onChange?.(values);
513
- } else {
514
- inputHandler.setValue([...Array().concat(values), option.value ]);
515
- onChange?.([...Array().concat(values), option.value]);
516
- }
517
- }
518
- setTimeout(() => inputHandler.setFocus(false), 120);
519
- }}
520
- >
521
- {selected && (
522
- <FontAwesomeIcon
523
- icon={faCheck}
524
- className="mr-2 text-sm"
525
- />
526
- )}
527
- {option.label}
528
- </li>
529
- );
530
- })}
531
- </ul>
532
- </div>
533
- )}
534
-
535
- {invalidMessage && (
536
- <small className={cn("input-error-message", pcn<CT>(className, "error"))}>{invalidMessage}</small>
537
- )}
538
- </div>
539
- </>
540
- );
541
- }