@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.
@@ -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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bacano/sdk",
3
- "version": "1.1.19",
3
+ "version": "1.1.20",
4
4
  "description": "TypeScript SDK for building websites on the Bacano ERP",
5
5
  "main": "./index.cjs",
6
6
  "module": "./index.js",
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 [values, setValues] = (0, import_react3.useState)({});
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) => setValues((current) => ({ ...current, [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 [values, setValues] = useState2({});
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) => setValues((current) => ({ ...current, [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) {