@zauru-sdk/components 1.0.99 → 1.0.100

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 (95) hide show
  1. package/CHANGELOG.md +8 -0
  2. package/dist/Form/Checkbox/index.d.ts +1 -3
  3. package/dist/Form/DatePicker/index.d.ts +1 -3
  4. package/dist/Form/FileUpload/index.d.ts +1 -2
  5. package/dist/Form/ReactZodForm/index.d.ts +12 -0
  6. package/dist/Form/SelectField/index.d.ts +6 -9
  7. package/dist/Form/TextArea/index.d.ts +1 -3
  8. package/dist/Form/TextField/index.d.ts +1 -3
  9. package/dist/Form/TimePicker/index.d.ts +1 -2
  10. package/dist/Form/YesNo/index.d.ts +1 -0
  11. package/dist/Form/index.d.ts +1 -2
  12. package/dist/Layouts/homeLayout/index.d.ts +3 -1
  13. package/dist/Modal/Modal.d.ts +1 -1
  14. package/dist/Zendesk/zendesk.config.d.ts +1 -1
  15. package/dist/cjs/Alerts/StaticAlert.js +0 -6
  16. package/dist/cjs/Buttons/Button.js +13 -2
  17. package/dist/cjs/DynamicTable/DynamicPrintTable.js +2 -2
  18. package/dist/cjs/DynamicTable/DynamicTable.js +3 -3
  19. package/dist/cjs/DynamicTable/GenericDynamicTable.js +4 -5
  20. package/dist/cjs/Footer/Footer.js +1 -1
  21. package/dist/cjs/Form/Checkbox/index.js +14 -14
  22. package/dist/cjs/Form/Checklist/index.js +1 -1
  23. package/dist/cjs/Form/DatePicker/index.js +14 -13
  24. package/dist/cjs/Form/DynamicBaculoForm/index.js +1 -1
  25. package/dist/cjs/Form/FileUpload/index.js +25 -13
  26. package/dist/cjs/Form/ReactZodForm/index.js +31 -0
  27. package/dist/cjs/Form/SelectField/index.js +118 -73
  28. package/dist/cjs/Form/TextArea/index.js +15 -15
  29. package/dist/cjs/Form/TextField/index.js +20 -16
  30. package/dist/cjs/Form/TimePicker/index.js +17 -15
  31. package/dist/cjs/Form/YesNo/index.js +12 -6
  32. package/dist/cjs/Form/index.js +1 -2
  33. package/dist/cjs/Layouts/homeLayout/index.js +45 -8
  34. package/dist/cjs/Modal/Modal.js +1 -2
  35. package/dist/cjs/NavBar/NavBar.js +12 -17
  36. package/dist/cjs/Table/ZauruTable.js +11 -4
  37. package/dist/cjs/WithTooltip/WithTooltip.js +1 -1
  38. package/dist/cjs/Zendesk/zendesk.config.js +7 -9
  39. package/dist/esm/Alerts/StaticAlert.js +0 -6
  40. package/dist/esm/Buttons/Button.js +13 -2
  41. package/dist/esm/DynamicTable/DynamicPrintTable.js +4 -4
  42. package/dist/esm/DynamicTable/DynamicTable.js +6 -6
  43. package/dist/esm/DynamicTable/GenericDynamicTable.js +7 -8
  44. package/dist/esm/Footer/Footer.js +1 -1
  45. package/dist/esm/Form/Checkbox/index.js +13 -12
  46. package/dist/esm/Form/Checklist/index.js +2 -2
  47. package/dist/esm/Form/DatePicker/index.js +13 -11
  48. package/dist/esm/Form/DynamicBaculoForm/index.js +2 -2
  49. package/dist/esm/Form/FileUpload/index.js +24 -11
  50. package/dist/esm/Form/ReactZodForm/index.js +27 -0
  51. package/dist/esm/Form/SelectField/index.js +118 -49
  52. package/dist/esm/Form/TextArea/index.js +14 -13
  53. package/dist/esm/Form/TextField/index.js +19 -14
  54. package/dist/esm/Form/TimePicker/index.js +16 -13
  55. package/dist/esm/Form/YesNo/index.js +12 -6
  56. package/dist/esm/Form/index.js +1 -2
  57. package/dist/esm/Layouts/homeLayout/index.js +46 -9
  58. package/dist/esm/Modal/Modal.js +1 -2
  59. package/dist/esm/NavBar/NavBar.js +12 -17
  60. package/dist/esm/Table/ZauruTable.js +11 -4
  61. package/dist/esm/WithTooltip/WithTooltip.js +2 -2
  62. package/dist/esm/Zendesk/zendesk.config.js +7 -6
  63. package/package.json +6 -3
  64. package/src/Alerts/StaticAlert.tsx +0 -10
  65. package/src/Buttons/Button.tsx +24 -4
  66. package/src/DynamicTable/DynamicPrintTable.tsx +5 -6
  67. package/src/DynamicTable/DynamicTable.tsx +7 -7
  68. package/src/DynamicTable/GenericDynamicTable.tsx +7 -8
  69. package/src/Footer/Footer.tsx +1 -1
  70. package/src/Form/Checkbox/index.tsx +21 -18
  71. package/src/Form/Checklist/index.tsx +2 -2
  72. package/src/Form/DatePicker/index.tsx +22 -19
  73. package/src/Form/DynamicBaculoForm/index.tsx +2 -2
  74. package/src/Form/FileUpload/index.tsx +29 -14
  75. package/src/Form/ReactZodForm/index.tsx +60 -0
  76. package/src/Form/SelectField/index.tsx +246 -130
  77. package/src/Form/TextArea/index.tsx +22 -19
  78. package/src/Form/TextField/index.tsx +25 -18
  79. package/src/Form/TimePicker/index.tsx +25 -18
  80. package/src/Form/YesNo/index.tsx +20 -7
  81. package/src/Form/index.ts +1 -2
  82. package/src/Layouts/homeLayout/index.tsx +114 -21
  83. package/src/Modal/Modal.tsx +2 -5
  84. package/src/NavBar/NavBar.tsx +35 -46
  85. package/src/Table/ZauruTable.tsx +11 -4
  86. package/src/WithTooltip/WithTooltip.tsx +8 -7
  87. package/src/Zendesk/zendesk.config.ts +8 -6
  88. package/dist/Form/FormLayout/index.d.ts +0 -11
  89. package/dist/Form/RadioButtonGroup/index.d.ts +0 -20
  90. package/dist/cjs/Form/FormLayout/index.js +0 -11
  91. package/dist/cjs/Form/RadioButtonGroup/index.js +0 -26
  92. package/dist/esm/Form/FormLayout/index.js +0 -7
  93. package/dist/esm/Form/RadioButtonGroup/index.js +0 -21
  94. package/src/Form/FormLayout/index.tsx +0 -37
  95. package/src/Form/RadioButtonGroup/index.tsx +0 -108
@@ -1,25 +1,21 @@
1
1
  import { IdeaIconSVG } from "@zauru-sdk/icons";
2
- import { useAppSelector } from "@zauru-sdk/redux";
3
2
  import { SelectFieldOption } from "@zauru-sdk/types";
4
- import { useEffect, useState } from "react";
5
- import type { SingleValue, InputActionMeta } from "react-select";
6
- import Select, { components } from "react-select";
3
+ import React, { useEffect, useState, useRef, KeyboardEvent } from "react";
7
4
  import { LoadingInputSkeleton } from "../../Skeletons/index.js";
5
+ import { useFormContext, Controller } from "react-hook-form";
8
6
 
9
7
  type Props = {
10
8
  id?: string;
11
- formName?: string;
12
9
  name?: string;
13
10
  title?: string;
14
- defaultValue?: SingleValue<SelectFieldOption>;
15
- defaultValueMulti?: SingleValue<SelectFieldOption>[];
11
+ defaultValue?: SelectFieldOption;
12
+ defaultValueMulti?: SelectFieldOption[];
16
13
  helpText?: string;
17
14
  options: Array<SelectFieldOption>;
18
- onChange?: (value: SingleValue<SelectFieldOption>) => void;
19
- onChangeMulti?: (value: Array<SingleValue<SelectFieldOption>>) => void;
20
- onInputChange?: (newValue: string, actionMeta: InputActionMeta) => void;
15
+ onChange?: (value: SelectFieldOption | null) => void;
16
+ onChangeMulti?: (value: SelectFieldOption[]) => void;
17
+ onInputChange?: (newValue: string) => void;
21
18
  isClearable?: boolean;
22
- error?: string | undefined;
23
19
  disabled?: boolean;
24
20
  menuIsOpen?: boolean;
25
21
  readOnly?: boolean;
@@ -27,13 +23,10 @@ type Props = {
27
23
  loading?: boolean;
28
24
  hint?: string;
29
25
  className?: string;
26
+ required?: boolean;
30
27
  };
31
28
 
32
- const Input = (props: any) => (
33
- <components.Input {...props} readOnly={props.selectProps.isReadOnly} />
34
- );
35
-
36
- export const SelectFieldWithoutValidation = (props: Props) => {
29
+ export const SelectField = (props: Props) => {
37
30
  const {
38
31
  id,
39
32
  name,
@@ -46,46 +39,164 @@ export const SelectFieldWithoutValidation = (props: Props) => {
46
39
  onChange,
47
40
  onChangeMulti,
48
41
  isClearable = false,
49
- error = false,
50
42
  disabled = false,
51
43
  readOnly = false,
52
44
  isMulti = false,
53
45
  loading = false,
54
46
  className = "",
55
47
  onInputChange,
48
+ required,
56
49
  } = props;
57
50
 
58
- const [value, setValue] = useState<SingleValue<SelectFieldOption>>(
51
+ const [value, setValue] = useState<SelectFieldOption | null>(
59
52
  defaultValue || null
60
53
  );
61
54
  const [valueMulti, setValueMulti] =
62
- useState<SingleValue<SelectFieldOption>[]>(defaultValueMulti);
63
- const [inputValue, setInputValue] = useState("");
55
+ useState<SelectFieldOption[]>(defaultValueMulti);
56
+ const [inputValue, setInputValue] = useState(defaultValue?.label || "");
64
57
  const [showTooltip, setShowTooltip] = useState<boolean>(false);
65
- const [isClient, setIsClient] = useState(typeof window !== "undefined");
58
+ const [isOpen, setIsOpen] = useState<boolean>(false);
59
+ const [filteredOptions, setFilteredOptions] = useState(options);
60
+ const [highlightedIndex, setHighlightedIndex] = useState<number>(-1);
61
+ const selectRef = useRef<HTMLDivElement>(null);
62
+ const optionsRef = useRef<HTMLUListElement>(null);
63
+ const [isTabPressed, setIsTabPressed] = useState<boolean>(false);
64
+ const [isEnterPressed, setIsEnterPressed] = useState<boolean>(false);
65
+ const [isSearching, setIsSearching] = useState<boolean>(false);
66
+ const {
67
+ control,
68
+ formState: { errors },
69
+ setValue: setFormValue,
70
+ } = useFormContext() || { formState: {} };
71
+ const error = errors ? errors[props.name ?? "-1"] : undefined;
66
72
 
67
- const menuIsOpen = readOnly ? false : props?.menuIsOpen;
68
73
  const color = error ? "red" : "gray";
69
- let documentRef = null;
70
-
71
74
  const isReadOnly = disabled || readOnly;
72
75
  const bgColor = isReadOnly ? "bg-gray-200" : `bg-${color}-50`;
73
76
  const textColor = isReadOnly ? "text-gray-500" : `text-${color}-900`;
74
77
  const borderColor = isReadOnly ? "border-gray-300" : `border-${color}-500`;
75
78
 
76
- if (typeof window !== "undefined") {
77
- documentRef = document;
78
- }
79
-
80
79
  useEffect(() => {
81
- setValue(defaultValue || null);
82
- }, [defaultValue]);
80
+ setFilteredOptions(options);
81
+ }, [options]);
83
82
 
84
83
  useEffect(() => {
85
- setIsClient(true);
84
+ const handleClickOutside = (event: MouseEvent) => {
85
+ if (
86
+ selectRef.current &&
87
+ !selectRef.current.contains(event.target as Node)
88
+ ) {
89
+ setIsOpen(false);
90
+ }
91
+ };
92
+
93
+ if (defaultValue) {
94
+ setValue(defaultValue);
95
+ setInputValue(defaultValue.label);
96
+ setFormValue(name || "", defaultValue);
97
+ }
98
+
99
+ document.addEventListener("mousedown", handleClickOutside);
100
+ return () => {
101
+ document.removeEventListener("mousedown", handleClickOutside);
102
+ };
86
103
  }, []);
87
104
 
88
- if (!isClient || loading || !documentRef) {
105
+ const handleInputChange = (e: React.ChangeEvent<HTMLInputElement>) => {
106
+ const newValue = e.target.value;
107
+ setInputValue(newValue);
108
+ onInputChange && onInputChange(newValue);
109
+ setIsSearching(true);
110
+ setFilteredOptions(
111
+ options.filter((option) =>
112
+ option.label.toLowerCase().includes(newValue.toLowerCase())
113
+ )
114
+ );
115
+ };
116
+
117
+ const handleOptionClick = (option: SelectFieldOption) => {
118
+ if (isMulti) {
119
+ const newValue = valueMulti.some((v) => v.value === option.value)
120
+ ? valueMulti.filter((v) => v.value !== option.value)
121
+ : [...valueMulti, option];
122
+ setValueMulti(newValue);
123
+ onChangeMulti && onChangeMulti(newValue);
124
+ setFormValue(name || "", newValue);
125
+ } else {
126
+ setValue(option);
127
+ setInputValue(option.label);
128
+ onChange && onChange(option);
129
+ setFormValue(name || "", option);
130
+ }
131
+ setIsOpen(false);
132
+ };
133
+
134
+ const handleClear = () => {
135
+ if (isMulti) {
136
+ setValueMulti([]);
137
+ onChangeMulti && onChangeMulti([]);
138
+ setFormValue(name || "", []);
139
+ } else {
140
+ setValue(null);
141
+ onChange && onChange(null);
142
+ setFormValue(name || "", null);
143
+ }
144
+ setInputValue("");
145
+ };
146
+
147
+ const handleBlur = () => {
148
+ setTimeout(() => {
149
+ if (
150
+ isTabPressed &&
151
+ filteredOptions.length > 0 &&
152
+ !isEnterPressed &&
153
+ isSearching
154
+ ) {
155
+ handleOptionClick(filteredOptions[0]);
156
+ }
157
+ setIsTabPressed(false);
158
+ setIsEnterPressed(false);
159
+ setIsSearching(false);
160
+ setIsOpen(false);
161
+ }, 200);
162
+ };
163
+
164
+ const handleKeyDown = (e: KeyboardEvent<HTMLInputElement>) => {
165
+ if (e.key === "Tab") {
166
+ setIsTabPressed(true);
167
+ } else if (e.key === "ArrowDown") {
168
+ e.preventDefault();
169
+ setHighlightedIndex((prevIndex) =>
170
+ prevIndex < filteredOptions.length - 1 ? prevIndex + 1 : 0
171
+ );
172
+ scrollToHighlightedOption();
173
+ } else if (e.key === "ArrowUp") {
174
+ e.preventDefault();
175
+ setHighlightedIndex((prevIndex) =>
176
+ prevIndex > 0 ? prevIndex - 1 : filteredOptions.length - 1
177
+ );
178
+ scrollToHighlightedOption();
179
+ } else if (e.key === "Enter" && highlightedIndex !== -1) {
180
+ e.preventDefault();
181
+ setIsEnterPressed(true);
182
+ handleOptionClick(filteredOptions[highlightedIndex]);
183
+ }
184
+ };
185
+
186
+ const scrollToHighlightedOption = () => {
187
+ if (optionsRef.current && optionsRef.current.children[highlightedIndex]) {
188
+ const highlightedOption = optionsRef.current.children[
189
+ highlightedIndex
190
+ ] as HTMLElement;
191
+ highlightedOption.scrollIntoView({
192
+ block: "center",
193
+ inline: "center",
194
+ behavior: "smooth",
195
+ });
196
+ }
197
+ };
198
+
199
+ if (loading) {
89
200
  return (
90
201
  <>
91
202
  {title && (
@@ -108,78 +219,8 @@ export const SelectFieldWithoutValidation = (props: Props) => {
108
219
  );
109
220
  }
110
221
 
111
- const handleOnChange = (
112
- selection: SingleValue<SelectFieldOption> | unknown
113
- ) => {
114
- // Verificar si el valor de selección es un objeto con propiedades 'value' y 'label'
115
- if (
116
- typeof selection === "object" &&
117
- selection !== null &&
118
- "value" in selection &&
119
- "label" in selection
120
- ) {
121
- setValue(selection as SingleValue<SelectFieldOption>);
122
- onChange && onChange(selection as SingleValue<SelectFieldOption>);
123
- } else {
124
- setValue(null);
125
- onChange && onChange(null);
126
- }
127
- };
128
-
129
- const handleOnChangeMulti = (
130
- selection: SingleValue<SelectFieldOption>[] | unknown
131
- ) => {
132
- if (Array.isArray(selection)) {
133
- setValueMulti(selection as SingleValue<SelectFieldOption>[]);
134
- onChangeMulti &&
135
- onChangeMulti(selection as SingleValue<SelectFieldOption>[]);
136
- } else {
137
- setValueMulti([]);
138
- onChangeMulti && onChangeMulti([]);
139
- }
140
- };
141
-
142
- const selectComponent = (
143
- <>
144
- <Select
145
- className={`block w-full rounded-md ${bgColor} ${borderColor} ${textColor} shadow-sm focus:border-indigo-500 focus:ring-indigo-500 sm:text-sm`}
146
- id={isMulti ? undefined : id}
147
- instanceId={isMulti ? undefined : id}
148
- isDisabled={disabled}
149
- name={isMulti ? undefined : name}
150
- options={options}
151
- onChange={isMulti ? handleOnChangeMulti : handleOnChange}
152
- defaultValue={isMulti ? valueMulti : value}
153
- onInputChange={(newValue: string, actionMeta: InputActionMeta) => {
154
- setInputValue(newValue);
155
- onInputChange && onInputChange(newValue, actionMeta);
156
- }}
157
- inputValue={inputValue}
158
- onMenuOpen={() => {}}
159
- onMenuClose={() => {}}
160
- menuPortalTarget={documentRef?.body}
161
- styles={{ menuPortal: (base) => ({ ...base, zIndex: 9999 }) }}
162
- isClearable={isClearable}
163
- isSearchable={true}
164
- components={{ Input }}
165
- menuIsOpen={menuIsOpen}
166
- //windowThreshold={50}
167
- isMulti={isMulti}
168
- />
169
- {isMulti && (
170
- <input
171
- hidden
172
- readOnly
173
- name={name}
174
- value={valueMulti.map((x) => x?.value).join(",")}
175
- id={id}
176
- />
177
- )}
178
- </>
179
- );
180
-
181
222
  return (
182
- <div className={`col-span-6 sm:col-span-3 ${className}`}>
223
+ <div className={`col-span-6 sm:col-span-3 ${className}`} ref={selectRef}>
183
224
  {title && (
184
225
  <label
185
226
  htmlFor={error ? `${name}-error` : `${name}-success`}
@@ -190,30 +231,114 @@ export const SelectFieldWithoutValidation = (props: Props) => {
190
231
  }`}
191
232
  >
192
233
  {title}
234
+ {required && <span className="text-red-500">*</span>}
193
235
  </label>
194
236
  )}
195
- <div className="flex relative items-center">
196
- {selectComponent}
197
- {helpText && (
198
- <div className="flex items-center relative ml-3">
199
- <div
200
- className="relative cursor-pointer"
201
- onMouseEnter={() => setShowTooltip(true)}
202
- onMouseLeave={() => setShowTooltip(false)}
203
- >
204
- <IdeaIconSVG />
205
- {showTooltip && (
206
- <div className="absolute -left-48 top-0 mt-8 p-2 bg-white border rounded shadow text-black z-50">
207
- {helpText}
208
- </div>
209
- )}
210
- </div>
211
- </div>
237
+ <div className="relative">
238
+ <Controller
239
+ name={name || ""}
240
+ control={control}
241
+ rules={{ required }}
242
+ defaultValue={defaultValue || (isMulti ? [] : null)}
243
+ render={({ field }) => (
244
+ <input
245
+ {...field}
246
+ type="text"
247
+ id={id}
248
+ value={inputValue}
249
+ onFocus={() => setIsOpen(true)}
250
+ onBlur={handleBlur}
251
+ onKeyDown={handleKeyDown}
252
+ readOnly={isReadOnly}
253
+ disabled={disabled}
254
+ className={`block w-full rounded-md ${bgColor} ${borderColor} ${textColor} shadow-sm focus:border-indigo-500 focus:ring-indigo-500 sm:text-sm`}
255
+ placeholder={
256
+ isMulti ? "Select options..." : "Select an option..."
257
+ }
258
+ onChange={(e) => {
259
+ field.onChange(e);
260
+ handleInputChange(e);
261
+ }}
262
+ />
263
+ )}
264
+ />
265
+ {isClearable && (value || valueMulti.length > 0) && (
266
+ <button
267
+ type="button"
268
+ onClick={handleClear}
269
+ className="absolute inset-y-0 right-0 pr-3 flex items-center"
270
+ >
271
+ ×
272
+ </button>
273
+ )}
274
+ {isOpen && !isReadOnly && (
275
+ <ul
276
+ ref={optionsRef}
277
+ className="absolute z-10 mt-1 w-full bg-white shadow-lg max-h-60 rounded-md py-1 text-base ring-1 ring-black ring-opacity-5 overflow-auto focus:outline-none sm:text-sm"
278
+ >
279
+ {filteredOptions.map((option, index) => (
280
+ <li
281
+ key={`${option.value}-${index}`}
282
+ className={`cursor-pointer select-none relative py-2 pl-3 pr-9 ${
283
+ (
284
+ isMulti
285
+ ? valueMulti.some((v) => v.value === option.value)
286
+ : value?.value === option.value
287
+ )
288
+ ? "text-white bg-indigo-600"
289
+ : index === highlightedIndex
290
+ ? "text-black bg-sky-200"
291
+ : "text-gray-900"
292
+ }`}
293
+ onClick={() => handleOptionClick(option)}
294
+ onMouseEnter={() => setHighlightedIndex(index)}
295
+ onMouseLeave={() => setHighlightedIndex(-1)}
296
+ >
297
+ {option.label}
298
+ </li>
299
+ ))}
300
+ </ul>
212
301
  )}
213
302
  </div>
303
+ {isMulti && (
304
+ <div className="mt-2 flex flex-wrap gap-2">
305
+ {valueMulti.map((option, index) => (
306
+ <span
307
+ key={`${option.value}-${index}`}
308
+ className="bg-blue-100 text-blue-800 text-xs font-semibold mr-2 px-2.5 py-0.5 rounded"
309
+ >
310
+ {option.label}
311
+ <button
312
+ type="button"
313
+ onClick={() => handleOptionClick(option)}
314
+ className="ml-1 text-blue-600 hover:text-blue-800"
315
+ >
316
+ ×
317
+ </button>
318
+ </span>
319
+ ))}
320
+ </div>
321
+ )}
322
+ {helpText && (
323
+ <div className="flex items-center relative mt-1">
324
+ <div
325
+ className="relative cursor-pointer"
326
+ onMouseEnter={() => setShowTooltip(true)}
327
+ onMouseLeave={() => setShowTooltip(false)}
328
+ >
329
+ <IdeaIconSVG />
330
+ {showTooltip && (
331
+ <div className="absolute -left-48 top-0 mt-8 p-2 bg-white border rounded shadow text-black z-50">
332
+ {helpText}
333
+ </div>
334
+ )}
335
+ </div>
336
+ </div>
337
+ )}
214
338
  {error && (
215
339
  <p className={`mt-2 text-sm text-${color}-600 dark:text-${color}-500`}>
216
- <span className="font-medium">Oops!</span> {error}
340
+ <span className="font-medium">Oops!</span>{" "}
341
+ {error?.message?.toString() || "Error desconocido"}
217
342
  </p>
218
343
  )}
219
344
  {!error && hint && (
@@ -226,12 +351,3 @@ export const SelectFieldWithoutValidation = (props: Props) => {
226
351
  </div>
227
352
  );
228
353
  };
229
-
230
- export const SelectField = (props: Props) => {
231
- const { formValidations } = useAppSelector((state) => state.formValidation);
232
- const error = formValidations[props.formName ?? "-1"]?.[props.name ?? "-1"];
233
-
234
- props = { ...props, error };
235
-
236
- return <SelectFieldWithoutValidation {...props} />;
237
- };
@@ -1,10 +1,9 @@
1
- import { useAppSelector } from "@zauru-sdk/redux";
2
1
  import React, { useEffect, useState } from "react";
2
+ import { useFormContext } from "react-hook-form";
3
3
 
4
4
  type Props = {
5
5
  id?: string;
6
6
  name: string;
7
- formName?: string;
8
7
  title?: string;
9
8
  defaultValue?: string | number;
10
9
  hidden?: boolean;
@@ -14,14 +13,14 @@ type Props = {
14
13
  onKeyDown?: (event: React.KeyboardEvent) => void;
15
14
  disabled?: boolean;
16
15
  readOnly?: boolean;
17
- error?: string | undefined;
18
16
  rows?: number;
19
17
  cols?: number;
20
18
  stopChangeEvents?: boolean;
21
19
  className?: string;
20
+ required?: boolean;
22
21
  };
23
22
 
24
- export const TextAreaWithoutValidation = (props: Props) => {
23
+ export const TextArea = (props: Props) => {
25
24
  const {
26
25
  id,
27
26
  name,
@@ -32,15 +31,23 @@ export const TextAreaWithoutValidation = (props: Props) => {
32
31
  onChange,
33
32
  onKeyDown,
34
33
  disabled = false,
35
- error = false,
36
34
  readOnly = false,
37
35
  rows,
38
36
  cols,
39
37
  stopChangeEvents,
40
38
  className = "",
39
+ required,
41
40
  } = props;
42
41
 
43
42
  const [value, setValue] = useState(defaultValue);
43
+ const {
44
+ register: tempRegister,
45
+ formState: { errors },
46
+ } = useFormContext() || { formState: {} }; // Obtener el contexto solo si existe
47
+ const error = errors ? errors[props.name ?? "-1"] : undefined;
48
+ const register = tempRegister
49
+ ? tempRegister(props.name ?? "-1", { required })
50
+ : undefined; // Solo usar register si está disponible
44
51
 
45
52
  const color = error ? "red" : "gray";
46
53
  const isReadOnly = disabled || readOnly;
@@ -56,15 +63,19 @@ export const TextAreaWithoutValidation = (props: Props) => {
56
63
  return (
57
64
  <textarea
58
65
  id={id ?? name}
59
- name={name}
60
66
  value={defaultValue}
61
67
  readOnly={true}
62
68
  hidden={true}
69
+ {...(register ?? {})}
70
+ name={name}
63
71
  />
64
72
  );
65
73
  }
66
74
 
67
75
  const handleInputChange = (event: React.ChangeEvent<HTMLTextAreaElement>) => {
76
+ if (register) {
77
+ register.onChange(event);
78
+ }
68
79
  if (stopChangeEvents) {
69
80
  event.stopPropagation();
70
81
  event.preventDefault();
@@ -81,10 +92,10 @@ export const TextAreaWithoutValidation = (props: Props) => {
81
92
  className={`block text-sm font-medium text-${color}-700 dark:text-${color}-500`}
82
93
  >
83
94
  {title}
95
+ {required && <span className="text-red-500">*</span>}
84
96
  </label>
85
97
  )}
86
98
  <textarea
87
- name={name}
88
99
  readOnly={readOnly}
89
100
  disabled={disabled}
90
101
  id={id ?? name}
@@ -92,15 +103,17 @@ export const TextAreaWithoutValidation = (props: Props) => {
92
103
  value={value}
93
104
  rows={rows}
94
105
  cols={cols}
95
- onChange={handleInputChange}
96
106
  onKeyDown={(event: React.KeyboardEvent) => {
97
107
  onKeyDown && onKeyDown(event);
98
108
  }}
99
109
  className={`mt-1 block w-full rounded-md ${bgColor} ${borderColor} ${textColor} shadow-sm focus:border-indigo-500 focus:ring-indigo-500 sm:text-sm`}
110
+ {...(register ?? {})}
111
+ name={name}
112
+ onChange={handleInputChange}
100
113
  />
101
114
  {error && (
102
115
  <p className={`mt-2 text-sm text-${color}-600 dark:text-${color}-500`}>
103
- <span className="font-medium">Oops!</span> {error}
116
+ <span className="font-medium">Oops!</span> {error.message?.toString()}
104
117
  </p>
105
118
  )}
106
119
  {!error && hint && (
@@ -113,13 +126,3 @@ export const TextAreaWithoutValidation = (props: Props) => {
113
126
  </div>
114
127
  );
115
128
  };
116
-
117
- //<reference> https://tailwindui.com/components/application-ui/forms/form-layouts
118
- export const TextArea = (props: Props) => {
119
- const { formValidations } = useAppSelector((state) => state.formValidation);
120
- const error = formValidations[props.formName ?? "-1"]?.[props.name ?? "-1"];
121
-
122
- props = { ...props, error };
123
-
124
- return <TextAreaWithoutValidation {...props} />;
125
- };