@zauru-sdk/components 1.0.99 → 1.0.101
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/CHANGELOG.md +16 -0
- package/dist/Form/Checkbox/index.d.ts +1 -3
- package/dist/Form/DatePicker/index.d.ts +1 -3
- package/dist/Form/FileUpload/index.d.ts +1 -2
- package/dist/Form/ReactZodForm/index.d.ts +12 -0
- package/dist/Form/SelectField/index.d.ts +6 -9
- package/dist/Form/TextArea/index.d.ts +1 -3
- package/dist/Form/TextField/index.d.ts +1 -3
- package/dist/Form/TimePicker/index.d.ts +1 -2
- package/dist/Form/YesNo/index.d.ts +1 -0
- package/dist/Form/index.d.ts +1 -2
- package/dist/Layouts/homeLayout/index.d.ts +3 -1
- package/dist/Modal/Modal.d.ts +1 -1
- package/dist/Zendesk/zendesk.config.d.ts +1 -1
- package/dist/cjs/Alerts/StaticAlert.js +0 -6
- package/dist/cjs/Buttons/Button.js +13 -2
- package/dist/cjs/DynamicTable/DynamicPrintTable.js +2 -2
- package/dist/cjs/DynamicTable/DynamicTable.js +3 -3
- package/dist/cjs/DynamicTable/GenericDynamicTable.js +4 -5
- package/dist/cjs/Footer/Footer.js +1 -1
- package/dist/cjs/Form/Checkbox/index.js +14 -14
- package/dist/cjs/Form/Checklist/index.js +1 -1
- package/dist/cjs/Form/DatePicker/index.js +14 -13
- package/dist/cjs/Form/DynamicBaculoForm/index.js +1 -1
- package/dist/cjs/Form/FileUpload/index.js +25 -13
- package/dist/cjs/Form/ReactZodForm/index.js +31 -0
- package/dist/cjs/Form/SelectField/index.js +118 -73
- package/dist/cjs/Form/TextArea/index.js +15 -15
- package/dist/cjs/Form/TextField/index.js +20 -16
- package/dist/cjs/Form/TimePicker/index.js +17 -15
- package/dist/cjs/Form/YesNo/index.js +12 -6
- package/dist/cjs/Form/index.js +1 -2
- package/dist/cjs/Layouts/homeLayout/index.js +45 -8
- package/dist/cjs/Modal/Modal.js +1 -2
- package/dist/cjs/NavBar/NavBar.js +12 -17
- package/dist/cjs/Table/ZauruTable.js +11 -4
- package/dist/cjs/WithTooltip/WithTooltip.js +1 -1
- package/dist/cjs/Zendesk/zendesk.config.js +7 -9
- package/dist/esm/Alerts/StaticAlert.js +0 -6
- package/dist/esm/Buttons/Button.js +13 -2
- package/dist/esm/DynamicTable/DynamicPrintTable.js +4 -4
- package/dist/esm/DynamicTable/DynamicTable.js +6 -6
- package/dist/esm/DynamicTable/GenericDynamicTable.js +7 -8
- package/dist/esm/Footer/Footer.js +1 -1
- package/dist/esm/Form/Checkbox/index.js +13 -12
- package/dist/esm/Form/Checklist/index.js +2 -2
- package/dist/esm/Form/DatePicker/index.js +13 -11
- package/dist/esm/Form/DynamicBaculoForm/index.js +2 -2
- package/dist/esm/Form/FileUpload/index.js +24 -11
- package/dist/esm/Form/ReactZodForm/index.js +27 -0
- package/dist/esm/Form/SelectField/index.js +118 -49
- package/dist/esm/Form/TextArea/index.js +14 -13
- package/dist/esm/Form/TextField/index.js +19 -14
- package/dist/esm/Form/TimePicker/index.js +16 -13
- package/dist/esm/Form/YesNo/index.js +12 -6
- package/dist/esm/Form/index.js +1 -2
- package/dist/esm/Layouts/homeLayout/index.js +46 -9
- package/dist/esm/Modal/Modal.js +1 -2
- package/dist/esm/NavBar/NavBar.js +12 -17
- package/dist/esm/Table/ZauruTable.js +11 -4
- package/dist/esm/WithTooltip/WithTooltip.js +2 -2
- package/dist/esm/Zendesk/zendesk.config.js +7 -6
- package/package.json +7 -4
- package/src/Alerts/StaticAlert.tsx +0 -10
- package/src/Buttons/Button.tsx +24 -4
- package/src/DynamicTable/DynamicPrintTable.tsx +5 -6
- package/src/DynamicTable/DynamicTable.tsx +7 -7
- package/src/DynamicTable/GenericDynamicTable.tsx +7 -8
- package/src/Footer/Footer.tsx +1 -1
- package/src/Form/Checkbox/index.tsx +21 -18
- package/src/Form/Checklist/index.tsx +2 -2
- package/src/Form/DatePicker/index.tsx +22 -19
- package/src/Form/DynamicBaculoForm/index.tsx +2 -2
- package/src/Form/FileUpload/index.tsx +29 -14
- package/src/Form/ReactZodForm/index.tsx +60 -0
- package/src/Form/SelectField/index.tsx +246 -130
- package/src/Form/TextArea/index.tsx +22 -19
- package/src/Form/TextField/index.tsx +25 -18
- package/src/Form/TimePicker/index.tsx +25 -18
- package/src/Form/YesNo/index.tsx +20 -7
- package/src/Form/index.ts +1 -2
- package/src/Layouts/homeLayout/index.tsx +114 -21
- package/src/Modal/Modal.tsx +2 -5
- package/src/NavBar/NavBar.tsx +35 -46
- package/src/Table/ZauruTable.tsx +11 -4
- package/src/WithTooltip/WithTooltip.tsx +8 -7
- package/src/Zendesk/zendesk.config.ts +8 -6
- package/dist/Form/FormLayout/index.d.ts +0 -11
- package/dist/Form/RadioButtonGroup/index.d.ts +0 -20
- package/dist/cjs/Form/FormLayout/index.js +0 -11
- package/dist/cjs/Form/RadioButtonGroup/index.js +0 -26
- package/dist/esm/Form/FormLayout/index.js +0 -7
- package/dist/esm/Form/RadioButtonGroup/index.js +0 -21
- package/src/Form/FormLayout/index.tsx +0 -37
- 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?:
|
|
15
|
-
defaultValueMulti?:
|
|
11
|
+
defaultValue?: SelectFieldOption;
|
|
12
|
+
defaultValueMulti?: SelectFieldOption[];
|
|
16
13
|
helpText?: string;
|
|
17
14
|
options: Array<SelectFieldOption>;
|
|
18
|
-
onChange?: (value:
|
|
19
|
-
onChangeMulti?: (value:
|
|
20
|
-
onInputChange?: (newValue: string
|
|
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
|
|
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<
|
|
51
|
+
const [value, setValue] = useState<SelectFieldOption | null>(
|
|
59
52
|
defaultValue || null
|
|
60
53
|
);
|
|
61
54
|
const [valueMulti, setValueMulti] =
|
|
62
|
-
useState<
|
|
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 [
|
|
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
|
-
|
|
82
|
-
}, [
|
|
80
|
+
setFilteredOptions(options);
|
|
81
|
+
}, [options]);
|
|
83
82
|
|
|
84
83
|
useEffect(() => {
|
|
85
|
-
|
|
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
|
-
|
|
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="
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
{
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
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>
|
|
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
|
|
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
|
-
};
|