@zauru-sdk/components 6.5.1 → 6.5.2
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 +11 -0
- package/dist/esm/Form/SelectField/index.js +47 -8
- package/package.json +2 -2
- package/src/Form/SelectField/index.tsx +67 -8
package/CHANGELOG.md
CHANGED
|
@@ -3,6 +3,17 @@
|
|
|
3
3
|
All notable changes to this project will be documented in this file.
|
|
4
4
|
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
|
5
5
|
|
|
6
|
+
## [6.5.2](https://github.com/intuitiva/zauru-typescript-sdk/compare/@zauru-sdk/components@6.5.1...@zauru-sdk/components@6.5.2) (2026-09-16)
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
### Bug Fixes
|
|
10
|
+
|
|
11
|
+
* sincronizar defaults async de SelectField ([5a06089](https://github.com/intuitiva/zauru-typescript-sdk/commit/5a06089bd2bbda775418123ed983ab98bf8cbef0))
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
|
|
6
17
|
## [6.5.1](https://github.com/intuitiva/zauru-typescript-sdk/compare/@zauru-sdk/components@6.5.0...@zauru-sdk/components@6.5.1) (2026-09-16)
|
|
7
18
|
|
|
8
19
|
**Note:** Version bump only for package @zauru-sdk/components
|
|
@@ -24,6 +24,10 @@ export const SelectField = (props) => {
|
|
|
24
24
|
const [highlightedIndex, setHighlightedIndex] = useState(-1);
|
|
25
25
|
const selectRef = useRef(null);
|
|
26
26
|
const optionsRef = useRef(null);
|
|
27
|
+
const hasManualSingleValue = useRef(false);
|
|
28
|
+
const hasManualMultiValue = useRef(false);
|
|
29
|
+
const lastSyncedDefaultValue = useRef(defaultValue?.value);
|
|
30
|
+
const lastSyncedDefaultValues = useRef(defaultValueMulti.map((option) => option.value));
|
|
27
31
|
const [isTabPressed, setIsTabPressed] = useState(false);
|
|
28
32
|
const [isSearching, setIsSearching] = useState(false);
|
|
29
33
|
// Use refs to store stable references to callbacks
|
|
@@ -52,18 +56,51 @@ export const SelectField = (props) => {
|
|
|
52
56
|
const bgColor = isReadOnly ? "bg-gray-200" : `bg-${color}-50`;
|
|
53
57
|
const textColor = isReadOnly ? "text-gray-500" : `text-${color}-900`;
|
|
54
58
|
const borderColor = isReadOnly ? "border-gray-300" : `border-${color}-200`;
|
|
55
|
-
|
|
59
|
+
const defaultValueMultiKey = defaultValueMulti
|
|
60
|
+
.map((option) => String(option.value))
|
|
61
|
+
.join("\u0000");
|
|
62
|
+
// Sincronizar defaults asíncronos con el estado visual y React Hook Form.
|
|
63
|
+
//
|
|
64
|
+
// Es importante depender del valor escalar y no del objeto completo: muchas
|
|
65
|
+
// pantallas construyen el option con `find()` en cada render. También solo
|
|
66
|
+
// reemplazamos el valor actual si todavía está vacío o conserva el último
|
|
67
|
+
// default sincronizado; así una selección manual no se pierde cuando el
|
|
68
|
+
// catálogo termina de cargar o se recrea el objeto de opciones.
|
|
56
69
|
useEffect(() => {
|
|
57
|
-
if (defaultValue
|
|
58
|
-
|
|
59
|
-
|
|
70
|
+
if (!defaultValue || isMulti || hasManualSingleValue.current) {
|
|
71
|
+
return;
|
|
72
|
+
}
|
|
73
|
+
const currentValue = value?.value;
|
|
74
|
+
const canSyncDefault = currentValue === undefined ||
|
|
75
|
+
currentValue === null ||
|
|
76
|
+
currentValue === lastSyncedDefaultValue.current;
|
|
77
|
+
if (canSyncDefault) {
|
|
78
|
+
if (currentValue !== defaultValue.value) {
|
|
79
|
+
setValue(defaultValue);
|
|
80
|
+
setInputValue(defaultValue.label);
|
|
81
|
+
}
|
|
82
|
+
setFormValue?.(name || "", defaultValue.value);
|
|
60
83
|
}
|
|
61
|
-
|
|
84
|
+
lastSyncedDefaultValue.current = defaultValue.value;
|
|
85
|
+
}, [defaultValue?.value, isMulti, name, setFormValue]);
|
|
62
86
|
useEffect(() => {
|
|
63
|
-
if (!
|
|
64
|
-
|
|
87
|
+
if (!isMulti ||
|
|
88
|
+
defaultValueMulti.length === 0 ||
|
|
89
|
+
hasManualMultiValue.current) {
|
|
90
|
+
return;
|
|
91
|
+
}
|
|
92
|
+
const currentValues = valueMulti.map((option) => option.value);
|
|
93
|
+
const previousDefaultValues = lastSyncedDefaultValues.current;
|
|
94
|
+
const canSyncDefault = currentValues.length === 0 ||
|
|
95
|
+
areOptionArraysEqual(valueMulti, previousDefaultValues.map((value) => ({ value, label: "" })));
|
|
96
|
+
if (canSyncDefault) {
|
|
97
|
+
if (!areOptionArraysEqual(defaultValueMulti, valueMulti)) {
|
|
98
|
+
setValueMulti(defaultValueMulti);
|
|
99
|
+
}
|
|
100
|
+
setFormValue?.(name || "", defaultValueMulti.map((option) => option.value));
|
|
65
101
|
}
|
|
66
|
-
|
|
102
|
+
lastSyncedDefaultValues.current = defaultValueMulti.map((option) => option.value);
|
|
103
|
+
}, [defaultValueMultiKey, isMulti, name, setFormValue]);
|
|
67
104
|
useEffect(() => {
|
|
68
105
|
setFilteredOptions(options);
|
|
69
106
|
}, [options]);
|
|
@@ -80,6 +117,7 @@ export const SelectField = (props) => {
|
|
|
80
117
|
};
|
|
81
118
|
}, []);
|
|
82
119
|
const handleSetSingleValue = useCallback((value) => {
|
|
120
|
+
hasManualSingleValue.current = true;
|
|
83
121
|
if (value) {
|
|
84
122
|
setValue(value);
|
|
85
123
|
setInputValue(value.label);
|
|
@@ -97,6 +135,7 @@ export const SelectField = (props) => {
|
|
|
97
135
|
onChangeRef.current && onChangeRef.current(value ?? null);
|
|
98
136
|
}, [name, setFormValue]);
|
|
99
137
|
const handleAddMultiValue = useCallback((value) => {
|
|
138
|
+
hasManualMultiValue.current = true;
|
|
100
139
|
if (value) {
|
|
101
140
|
const existValue = options.some((v) => v.value === value.value);
|
|
102
141
|
const noEstaYaSeleccionado = !valueMulti.some((v) => v.value === value.value);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@zauru-sdk/components",
|
|
3
|
-
"version": "6.5.
|
|
3
|
+
"version": "6.5.2",
|
|
4
4
|
"description": "Componentes reutilizables en las WebApps de Zauru.",
|
|
5
5
|
"main": "./dist/esm/index.js",
|
|
6
6
|
"module": "./dist/esm/index.js",
|
|
@@ -62,5 +62,5 @@
|
|
|
62
62
|
"styled-components": "^5.3.5",
|
|
63
63
|
"zod": "^3.23.8"
|
|
64
64
|
},
|
|
65
|
-
"gitHead": "
|
|
65
|
+
"gitHead": "2189a91ba403d92b2bb4f3e84af9b52852e5cbcf"
|
|
66
66
|
}
|
|
@@ -81,6 +81,12 @@ export const SelectField = (props: Props) => {
|
|
|
81
81
|
const [highlightedIndex, setHighlightedIndex] = useState<number>(-1);
|
|
82
82
|
const selectRef = useRef<HTMLDivElement>(null);
|
|
83
83
|
const optionsRef = useRef<HTMLUListElement>(null);
|
|
84
|
+
const hasManualSingleValue = useRef(false);
|
|
85
|
+
const hasManualMultiValue = useRef(false);
|
|
86
|
+
const lastSyncedDefaultValue = useRef(defaultValue?.value);
|
|
87
|
+
const lastSyncedDefaultValues = useRef(
|
|
88
|
+
defaultValueMulti.map((option) => option.value),
|
|
89
|
+
);
|
|
84
90
|
const [isTabPressed, setIsTabPressed] = useState<boolean>(false);
|
|
85
91
|
const [isSearching, setIsSearching] = useState<boolean>(false);
|
|
86
92
|
|
|
@@ -119,20 +125,71 @@ export const SelectField = (props: Props) => {
|
|
|
119
125
|
const bgColor = isReadOnly ? "bg-gray-200" : `bg-${color}-50`;
|
|
120
126
|
const textColor = isReadOnly ? "text-gray-500" : `text-${color}-900`;
|
|
121
127
|
const borderColor = isReadOnly ? "border-gray-300" : `border-${color}-200`;
|
|
128
|
+
const defaultValueMultiKey = defaultValueMulti
|
|
129
|
+
.map((option) => String(option.value))
|
|
130
|
+
.join("\u0000");
|
|
122
131
|
|
|
123
|
-
// Sincronizar estado
|
|
132
|
+
// Sincronizar defaults asíncronos con el estado visual y React Hook Form.
|
|
133
|
+
//
|
|
134
|
+
// Es importante depender del valor escalar y no del objeto completo: muchas
|
|
135
|
+
// pantallas construyen el option con `find()` en cada render. También solo
|
|
136
|
+
// reemplazamos el valor actual si todavía está vacío o conserva el último
|
|
137
|
+
// default sincronizado; así una selección manual no se pierde cuando el
|
|
138
|
+
// catálogo termina de cargar o se recrea el objeto de opciones.
|
|
124
139
|
useEffect(() => {
|
|
125
|
-
if (defaultValue
|
|
126
|
-
|
|
127
|
-
setInputValue(defaultValue.label);
|
|
140
|
+
if (!defaultValue || isMulti || hasManualSingleValue.current) {
|
|
141
|
+
return;
|
|
128
142
|
}
|
|
129
|
-
|
|
143
|
+
|
|
144
|
+
const currentValue = value?.value;
|
|
145
|
+
const canSyncDefault =
|
|
146
|
+
currentValue === undefined ||
|
|
147
|
+
currentValue === null ||
|
|
148
|
+
currentValue === lastSyncedDefaultValue.current;
|
|
149
|
+
|
|
150
|
+
if (canSyncDefault) {
|
|
151
|
+
if (currentValue !== defaultValue.value) {
|
|
152
|
+
setValue(defaultValue);
|
|
153
|
+
setInputValue(defaultValue.label);
|
|
154
|
+
}
|
|
155
|
+
setFormValue?.(name || "", defaultValue.value);
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
lastSyncedDefaultValue.current = defaultValue.value;
|
|
159
|
+
}, [defaultValue?.value, isMulti, name, setFormValue]);
|
|
130
160
|
|
|
131
161
|
useEffect(() => {
|
|
132
|
-
if (
|
|
133
|
-
|
|
162
|
+
if (
|
|
163
|
+
!isMulti ||
|
|
164
|
+
defaultValueMulti.length === 0 ||
|
|
165
|
+
hasManualMultiValue.current
|
|
166
|
+
) {
|
|
167
|
+
return;
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
const currentValues = valueMulti.map((option) => option.value);
|
|
171
|
+
const previousDefaultValues = lastSyncedDefaultValues.current;
|
|
172
|
+
const canSyncDefault =
|
|
173
|
+
currentValues.length === 0 ||
|
|
174
|
+
areOptionArraysEqual(
|
|
175
|
+
valueMulti,
|
|
176
|
+
previousDefaultValues.map((value) => ({ value, label: "" })),
|
|
177
|
+
);
|
|
178
|
+
|
|
179
|
+
if (canSyncDefault) {
|
|
180
|
+
if (!areOptionArraysEqual(defaultValueMulti, valueMulti)) {
|
|
181
|
+
setValueMulti(defaultValueMulti);
|
|
182
|
+
}
|
|
183
|
+
setFormValue?.(
|
|
184
|
+
name || "",
|
|
185
|
+
defaultValueMulti.map((option) => option.value),
|
|
186
|
+
);
|
|
134
187
|
}
|
|
135
|
-
|
|
188
|
+
|
|
189
|
+
lastSyncedDefaultValues.current = defaultValueMulti.map(
|
|
190
|
+
(option) => option.value,
|
|
191
|
+
);
|
|
192
|
+
}, [defaultValueMultiKey, isMulti, name, setFormValue]);
|
|
136
193
|
|
|
137
194
|
useEffect(() => {
|
|
138
195
|
setFilteredOptions(options);
|
|
@@ -156,6 +213,7 @@ export const SelectField = (props: Props) => {
|
|
|
156
213
|
|
|
157
214
|
const handleSetSingleValue = useCallback(
|
|
158
215
|
(value?: SelectFieldOption) => {
|
|
216
|
+
hasManualSingleValue.current = true;
|
|
159
217
|
if (value) {
|
|
160
218
|
setValue(value);
|
|
161
219
|
setInputValue(value.label);
|
|
@@ -176,6 +234,7 @@ export const SelectField = (props: Props) => {
|
|
|
176
234
|
|
|
177
235
|
const handleAddMultiValue = useCallback(
|
|
178
236
|
(value?: SelectFieldOption) => {
|
|
237
|
+
hasManualMultiValue.current = true;
|
|
179
238
|
if (value) {
|
|
180
239
|
const existValue = options.some((v) => v.value === value.value);
|
|
181
240
|
const noEstaYaSeleccionado = !valueMulti.some(
|