@bacano/sdk 1.1.19 → 1.1.20
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/STOREFRONT_FORMS.md +51 -0
- package/package.json +1 -1
- package/react/forms.cjs +11 -2
- package/react/forms.d.ts +4 -0
- package/react/forms.js +11 -2
package/STOREFRONT_FORMS.md
CHANGED
|
@@ -35,6 +35,57 @@ idempotente estable y llama `client.forms.submitResponse(...)`. Un formulario
|
|
|
35
35
|
pausado muestra su mensaje de indisponibilidad y deja de operar sin reconstruir
|
|
36
36
|
el storefront.
|
|
37
37
|
|
|
38
|
+
## Preseleccionar desde un botón externo
|
|
39
|
+
|
|
40
|
+
Usa `values` y `onValuesChange` juntos para controlar el estado. El botón mezcla
|
|
41
|
+
solo el campo que cambia: no reemplaces todo el objeto ni desmontes el formulario
|
|
42
|
+
para preseleccionar. El visitante puede seguir editando cualquier campo.
|
|
43
|
+
|
|
44
|
+
```tsx
|
|
45
|
+
import { useRef, useState } from "react";
|
|
46
|
+
import { BacanoForm, type BacanoFormValues } from "@bacano/sdk/react/forms";
|
|
47
|
+
|
|
48
|
+
export function ProjectInquiry() {
|
|
49
|
+
const [values, setValues] = useState<BacanoFormValues>({});
|
|
50
|
+
const sectionRef = useRef<HTMLElement>(null);
|
|
51
|
+
|
|
52
|
+
return (
|
|
53
|
+
<>
|
|
54
|
+
<button
|
|
55
|
+
type="button"
|
|
56
|
+
onClick={() => {
|
|
57
|
+
setValues((current) => ({ ...current, producto: "gaia" }));
|
|
58
|
+
sectionRef.current?.scrollIntoView({ behavior: "smooth", block: "start" });
|
|
59
|
+
}}
|
|
60
|
+
>
|
|
61
|
+
Me interesa Gaia
|
|
62
|
+
</button>
|
|
63
|
+
<section ref={sectionRef}>
|
|
64
|
+
<BacanoForm
|
|
65
|
+
formKey="contacto"
|
|
66
|
+
values={values}
|
|
67
|
+
onValuesChange={setValues}
|
|
68
|
+
/>
|
|
69
|
+
</section>
|
|
70
|
+
</>
|
|
71
|
+
);
|
|
72
|
+
}
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
- `producto` debe ser la key real del campo publicado y `gaia` el `value`
|
|
76
|
+
real de la opción, no su label. Usa `string[]` para `multi_select` y booleanos
|
|
77
|
+
para `checkbox`. Las validaciones publicadas siguen aplicándose.
|
|
78
|
+
- Puedes inicializar `useState` con la preselección, incluso antes de cargar
|
|
79
|
+
la definición. Un cambio externo no reinicia los pasos ni los otros campos.
|
|
80
|
+
- `onValuesChange` entrega el objeto completo tras cada edición del visitante;
|
|
81
|
+
los cambios externos se hacen sobre el estado del componente padre.
|
|
82
|
+
- Las keys ajenas a la definición publicada no se envían. Si compartes un
|
|
83
|
+
componente entre distintos sitios o formularios, reinicia su estado al cambiar
|
|
84
|
+
de identidad; no reutilices los datos de un visitante entre formularios.
|
|
85
|
+
- Sin `onSubmit` se mantiene el envío oficial, incluyendo la selección. No
|
|
86
|
+
necesitas otro endpoint, eventos DOM ni un formulario paralelo.
|
|
87
|
+
- Omitir ambas props conserva el funcionamiento anterior, con estado interno.
|
|
88
|
+
|
|
38
89
|
## Estructura del formulario
|
|
39
90
|
|
|
40
91
|
La definición tiene tres niveles explícitos:
|
package/package.json
CHANGED
package/react/forms.cjs
CHANGED
|
@@ -260,7 +260,7 @@ function BacanoForm(props) {
|
|
|
260
260
|
const { form, loading, error } = useBacanoForm(props.formKey, {
|
|
261
261
|
initialForm: props.initialForm
|
|
262
262
|
});
|
|
263
|
-
const [
|
|
263
|
+
const [internalValues, setValues] = (0, import_react3.useState)({});
|
|
264
264
|
const [step, setStep] = (0, import_react3.useState)(0);
|
|
265
265
|
const [submitting, setSubmitting] = (0, import_react3.useState)(false);
|
|
266
266
|
const [submitted, setSubmitted] = (0, import_react3.useState)(false);
|
|
@@ -283,6 +283,11 @@ function BacanoForm(props) {
|
|
|
283
283
|
),
|
|
284
284
|
[fields, sections, steps]
|
|
285
285
|
);
|
|
286
|
+
const values = Object.fromEntries(
|
|
287
|
+
Object.entries(props.values ?? internalValues).filter(
|
|
288
|
+
([key]) => fieldKeys.has(key)
|
|
289
|
+
)
|
|
290
|
+
);
|
|
286
291
|
(0, import_react3.useEffect)(() => {
|
|
287
292
|
setStep(0);
|
|
288
293
|
setValues(
|
|
@@ -308,7 +313,11 @@ function BacanoForm(props) {
|
|
|
308
313
|
const isMultiStep = steps.length > 0;
|
|
309
314
|
const activeStep = isMultiStep ? steps[step] : null;
|
|
310
315
|
const isLastStep = !isMultiStep || step === steps.length - 1;
|
|
311
|
-
const setFieldValue = (key, value) =>
|
|
316
|
+
const setFieldValue = (key, value) => {
|
|
317
|
+
const nextValues = { ...values, [key]: value };
|
|
318
|
+
setValues(nextValues);
|
|
319
|
+
props.onValuesChange?.(nextValues);
|
|
320
|
+
};
|
|
312
321
|
const submit = async (event) => {
|
|
313
322
|
event.preventDefault();
|
|
314
323
|
if (!isLastStep) {
|
package/react/forms.d.ts
CHANGED
|
@@ -33,6 +33,10 @@ export interface BacanoFormClassNames {
|
|
|
33
33
|
}
|
|
34
34
|
export interface BacanoFormProps {
|
|
35
35
|
formKey: string;
|
|
36
|
+
/** Controlled values. Use together with onValuesChange; option values, not labels. */
|
|
37
|
+
values?: BacanoFormValues;
|
|
38
|
+
/** Receives the complete next values after a visitor edits a field. */
|
|
39
|
+
onValuesChange?(values: BacanoFormValues): void;
|
|
36
40
|
/** Definition embedded by a server/build; it is revalidated in runtime. */
|
|
37
41
|
initialForm?: WebsitePublishedForm | null;
|
|
38
42
|
/**
|
package/react/forms.js
CHANGED
|
@@ -242,7 +242,7 @@ function BacanoForm(props) {
|
|
|
242
242
|
const { form, loading, error } = useBacanoForm(props.formKey, {
|
|
243
243
|
initialForm: props.initialForm
|
|
244
244
|
});
|
|
245
|
-
const [
|
|
245
|
+
const [internalValues, setValues] = useState2({});
|
|
246
246
|
const [step, setStep] = useState2(0);
|
|
247
247
|
const [submitting, setSubmitting] = useState2(false);
|
|
248
248
|
const [submitted, setSubmitted] = useState2(false);
|
|
@@ -265,6 +265,11 @@ function BacanoForm(props) {
|
|
|
265
265
|
),
|
|
266
266
|
[fields, sections, steps]
|
|
267
267
|
);
|
|
268
|
+
const values = Object.fromEntries(
|
|
269
|
+
Object.entries(props.values ?? internalValues).filter(
|
|
270
|
+
([key]) => fieldKeys.has(key)
|
|
271
|
+
)
|
|
272
|
+
);
|
|
268
273
|
useEffect2(() => {
|
|
269
274
|
setStep(0);
|
|
270
275
|
setValues(
|
|
@@ -290,7 +295,11 @@ function BacanoForm(props) {
|
|
|
290
295
|
const isMultiStep = steps.length > 0;
|
|
291
296
|
const activeStep = isMultiStep ? steps[step] : null;
|
|
292
297
|
const isLastStep = !isMultiStep || step === steps.length - 1;
|
|
293
|
-
const setFieldValue = (key, value) =>
|
|
298
|
+
const setFieldValue = (key, value) => {
|
|
299
|
+
const nextValues = { ...values, [key]: value };
|
|
300
|
+
setValues(nextValues);
|
|
301
|
+
props.onValuesChange?.(nextValues);
|
|
302
|
+
};
|
|
294
303
|
const submit = async (event) => {
|
|
295
304
|
event.preventDefault();
|
|
296
305
|
if (!isLastStep) {
|