@wix/headless-forms 0.0.21 → 0.0.23

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.
@@ -1,6 +1,6 @@
1
1
  import React from 'react';
2
2
  import { type FormError } from '@wix/form-public';
3
- import { type CheckboxGroupProps, type CheckboxProps, type PhoneInputProps, type DateInputProps, type DatePickerProps, type DateTimeInputProps, type DropdownProps, type FileUploadProps, type MultilineAddressProps, type NumberInputProps, type RadioGroupProps, type RatingInputProps, type RichTextProps, type SignatureProps, type SubmitButtonProps, type TagsProps, type TextAreaProps, type TextInputProps, type TimeInputProps, type ProductListProps, type FixedPaymentProps, type PaymentInputProps, type DonationProps, type AppointmentProps, type ImageChoiceProps } from './types.js';
3
+ import { type CheckboxGroupProps, type CheckboxProps, type PhoneInputProps, type DateInputProps, type DatePickerProps, type DateTimeInputProps, type DropdownProps, type FileUploadProps, type MultilineAddressProps, type NumberInputProps, type RadioGroupProps, type RatingInputProps, type RichTextProps, type SignatureProps, type SubmitButtonProps, type TagsProps, type TextAreaProps, type TextInputProps, type TimeInputProps, type ProductListProps, type FixedPaymentProps, type PaymentInputProps, type DonationProps, type AppointmentProps, type ImageChoiceProps, type LoginBarProps } from './types.js';
4
4
  import { type FormServiceConfig } from '../services/form-service.js';
5
5
  /**
6
6
  * Props for the Form root component following the documented API
@@ -22,7 +22,9 @@ export interface RootProps {
22
22
  * @component
23
23
  * @param {RootProps} props - The component props
24
24
  * @param {React.ReactNode} props.children - Child components that will have access to form context
25
- * @param {FormServiceConfig} props.formServiceConfig - Form service configuration object
25
+ * @param {FormServiceConfig} props.formServiceConfig - Form service configuration object. Supports two patterns:
26
+ * - Pre-loaded form data: `{ form: Form, onSubmit?: Function, addressTemplates?: any[] }`
27
+ * - Lazy loading: `{ formId: string, namespace?: string, additionalMetadata?: Record<string, string | string[]>, onSubmit?: Function }`
26
28
  * @param {boolean} [props.asChild] - Whether to render as a child component
27
29
  * @param {string} [props.className] - CSS classes to apply to the root element
28
30
  * @example
@@ -62,6 +64,25 @@ export interface RootProps {
62
64
  * </Form.Root>
63
65
  * );
64
66
  * }
67
+ *
68
+ * // Pattern 3: With namespace and additional metadata (for bookings, etc.)
69
+ * function BookingFormPage({ formId }) {
70
+ * return (
71
+ * <Form.Root
72
+ * formServiceConfig={{
73
+ * formId,
74
+ * namespace: 'wix.bookings.form',
75
+ * additionalMetadata: { serviceId: ['service-123'] },
76
+ * }}
77
+ * >
78
+ * <Form.Loading className="flex justify-center p-4" />
79
+ * <Form.LoadingError className="text-destructive px-4 py-3 rounded mb-4" />
80
+ * <Form.Fields fieldMap={FIELD_MAP} />
81
+ * <Form.Error className="text-destructive p-4 rounded-lg mb-4" />
82
+ * <Form.Submitted className="text-green-500 p-4 rounded-lg mb-4" />
83
+ * </Form.Root>
84
+ * );
85
+ * }
65
86
  * ```
66
87
  */
67
88
  export declare const Root: React.ForwardRefExoticComponent<RootProps & React.RefAttributes<HTMLDivElement>>;
@@ -399,6 +420,7 @@ export interface FieldMap {
399
420
  DONATION: React.ComponentType<DonationProps>;
400
421
  APPOINTMENT: React.ComponentType<AppointmentProps>;
401
422
  IMAGE_CHOICE: React.ComponentType<ImageChoiceProps>;
423
+ LOGIN_BAR: React.ComponentType<LoginBarProps>;
402
424
  }
403
425
  /**
404
426
  * Props for the Form Fields component.
@@ -65,7 +65,9 @@ var TestIds;
65
65
  * @component
66
66
  * @param {RootProps} props - The component props
67
67
  * @param {React.ReactNode} props.children - Child components that will have access to form context
68
- * @param {FormServiceConfig} props.formServiceConfig - Form service configuration object
68
+ * @param {FormServiceConfig} props.formServiceConfig - Form service configuration object. Supports two patterns:
69
+ * - Pre-loaded form data: `{ form: Form, onSubmit?: Function, addressTemplates?: any[] }`
70
+ * - Lazy loading: `{ formId: string, namespace?: string, additionalMetadata?: Record<string, string | string[]>, onSubmit?: Function }`
69
71
  * @param {boolean} [props.asChild] - Whether to render as a child component
70
72
  * @param {string} [props.className] - CSS classes to apply to the root element
71
73
  * @example
@@ -105,11 +107,30 @@ var TestIds;
105
107
  * </Form.Root>
106
108
  * );
107
109
  * }
110
+ *
111
+ * // Pattern 3: With namespace and additional metadata (for bookings, etc.)
112
+ * function BookingFormPage({ formId }) {
113
+ * return (
114
+ * <Form.Root
115
+ * formServiceConfig={{
116
+ * formId,
117
+ * namespace: 'wix.bookings.form',
118
+ * additionalMetadata: { serviceId: ['service-123'] },
119
+ * }}
120
+ * >
121
+ * <Form.Loading className="flex justify-center p-4" />
122
+ * <Form.LoadingError className="text-destructive px-4 py-3 rounded mb-4" />
123
+ * <Form.Fields fieldMap={FIELD_MAP} />
124
+ * <Form.Error className="text-destructive p-4 rounded-lg mb-4" />
125
+ * <Form.Submitted className="text-green-500 p-4 rounded-lg mb-4" />
126
+ * </Form.Root>
127
+ * );
128
+ * }
108
129
  * ```
109
130
  */
110
131
  exports.Root = react_1.default.forwardRef((props, ref) => {
111
132
  const { children, formServiceConfig, asChild, ...otherProps } = props;
112
- return ((0, jsx_runtime_1.jsx)(Form_js_1.Root, { formServiceConfig: formServiceConfig, children: (0, jsx_runtime_1.jsx)(RootContent, { asChild: asChild, ref: ref, ...otherProps, children: children }) }));
133
+ return ((0, jsx_runtime_1.jsx)(Form_js_1.Root, { formServiceConfig: formServiceConfig, formRef: ref, children: (0, jsx_runtime_1.jsx)(RootContent, { asChild: asChild, ref: ref, ...otherProps, children: children }) }));
113
134
  });
114
135
  /**
115
136
  * Internal component to handle the Root content with service access.
@@ -528,16 +549,17 @@ exports.Fields = react_1.default.forwardRef((props, ref) => {
528
549
  const [formErrors, setFormErrors] = (0, react_1.useState)([]);
529
550
  const currentLocale = essentials_1.i18n.getLocale();
530
551
  const currentLanguage = essentials_1.i18n.getLanguage();
552
+ const formRef = (0, Form_js_1.useFormRef)();
531
553
  const handleFormValidate = (0, react_1.useCallback)((errors) => {
532
554
  setFormErrors(errors);
533
555
  }, []);
534
556
  return ((0, jsx_runtime_1.jsx)(Form_js_1.Fields, { children: ({ form, formValues, submitForm, handleForm, addressTemplates }) => {
535
557
  if (!form)
536
558
  return null;
537
- return ((0, jsx_runtime_1.jsx)("div", { ref: ref, children: (0, jsx_runtime_1.jsx)(form_public_1.FormProvider, { currency: 'USD', locale: currentLanguage, regionalFormat: currentLocale, addressTemplates: addressTemplates, children: (0, jsx_runtime_1.jsx)(form_public_1.UniqueFieldSuffixContextProvider, { parentId: form._id ?? '', children: (0, jsx_runtime_1.jsx)(FieldsWithForm, { form: form, values: formValues, onChange: handleForm, errors: formErrors, onValidate: handleFormValidate, fields: props.fieldMap, submitForm: submitForm, rowGapClassname: props.rowGapClassname, columnGapClassname: props.columnGapClassname }) }) }) }));
559
+ return ((0, jsx_runtime_1.jsx)("div", { ref: ref, children: (0, jsx_runtime_1.jsx)(form_public_1.FormProvider, { currency: 'USD', locale: currentLanguage, regionalFormat: currentLocale, addressTemplates: addressTemplates, children: (0, jsx_runtime_1.jsx)(form_public_1.UniqueFieldSuffixContextProvider, { parentId: form._id ?? '', children: (0, jsx_runtime_1.jsx)(FieldsWithForm, { form: form, values: formValues, onChange: handleForm, errors: formErrors, onValidate: handleFormValidate, fields: props.fieldMap, submitForm: submitForm, rowGapClassname: props.rowGapClassname, columnGapClassname: props.columnGapClassname, formRef: formRef }) }) }) }));
538
560
  } }));
539
561
  });
540
- const FieldsWithForm = ({ form, submitForm, values, onChange, errors, onValidate, fields: fieldMap, rowGapClassname, columnGapClassname, }) => {
562
+ const FieldsWithForm = ({ form, submitForm, values, onChange, errors, onValidate, fields: fieldMap, rowGapClassname, columnGapClassname, formRef, }) => {
541
563
  const coreUploadFile = async ({ file, formId, }) => {
542
564
  const uploadUrl = await (0, utils_1.getUploadUrl)(formId, file);
543
565
  if (uploadUrl === undefined) {
@@ -560,6 +582,7 @@ const FieldsWithForm = ({ form, submitForm, values, onChange, errors, onValidate
560
582
  submitForm,
561
583
  uploadFile: coreUploadFile,
562
584
  fieldMap,
585
+ forwardedRef: formRef,
563
586
  });
564
587
  if (!formData)
565
588
  return null;
@@ -1,12 +1,19 @@
1
+ import React from 'react';
1
2
  import { forms } from '@wix/forms';
2
3
  import { FormServiceConfig } from '../../services/form-service.js';
3
4
  import { FormValues } from '../types.js';
5
+ /**
6
+ * Hook to access the form ref from context
7
+ */
8
+ export declare function useFormRef(): React.Ref<any> | undefined;
4
9
  /**
5
10
  * Props for Root headless component
6
11
  */
7
12
  export interface RootProps {
8
13
  children: React.ReactNode;
9
14
  formServiceConfig: FormServiceConfig;
15
+ /** Optional ref to access form methods imperatively */
16
+ formRef?: React.Ref<any>;
10
17
  }
11
18
  /**
12
19
  * Root component that provides the Form service context to its children.
@@ -16,7 +23,9 @@ export interface RootProps {
16
23
  * @component
17
24
  * @param {RootProps} props - Component props
18
25
  * @param {React.ReactNode} props.children - Child components that will have access to form context
19
- * @param {FormServiceConfig} props.formServiceConfig - Configuration object containing form data
26
+ * @param {FormServiceConfig} props.formServiceConfig - Configuration object containing form data. Supports two patterns:
27
+ * - Pre-loaded form data: `{ form: Form, onSubmit?: Function, addressTemplates?: any[] }`
28
+ * - Lazy loading: `{ formId: string, namespace?: string, additionalMetadata?: Record<string, string | string[]>, onSubmit?: Function }`
20
29
  * @example
21
30
  * ```tsx
22
31
  * import { Form } from '@wix/headless-forms/react';
@@ -51,9 +60,30 @@ export interface RootProps {
51
60
  * </Form.Root>
52
61
  * );
53
62
  * }
63
+ *
64
+ * // Pattern 3: With namespace and additional metadata (for bookings, etc.)
65
+ * function BookingFormPage({ formId }) {
66
+ * return (
67
+ * <Form.Root
68
+ * formServiceConfig={{
69
+ * formId,
70
+ * namespace: 'wix.bookings.form',
71
+ * additionalMetadata: { serviceId: ['service-123'] },
72
+ * }}
73
+ * >
74
+ * <Form.Loading>
75
+ * {({ isLoading }) => isLoading ? <div>Loading form...</div> : null}
76
+ * </Form.Loading>
77
+ * <Form.LoadingError>
78
+ * {({ error, hasError }) => hasError ? <div>{error}</div> : null}
79
+ * </Form.LoadingError>
80
+ * <Form.Fields fieldMap={FIELD_MAP} />
81
+ * </Form.Root>
82
+ * );
83
+ * }
54
84
  * ```
55
85
  */
56
- export declare function Root({ formServiceConfig, children, }: RootProps): React.ReactNode;
86
+ export declare function Root({ formServiceConfig, formRef, children, }: RootProps): React.ReactNode;
57
87
  /**
58
88
  * Props for FormLoading headless component
59
89
  */
@@ -91,7 +121,7 @@ export interface FormLoadingRenderProps {
91
121
  * }
92
122
  * ```
93
123
  */
94
- export declare function Loading(props: FormLoadingProps): import("react").ReactNode;
124
+ export declare function Loading(props: FormLoadingProps): React.ReactNode;
95
125
  /**
96
126
  * Props for FormError headless component
97
127
  */
@@ -133,7 +163,7 @@ export interface FormErrorRenderProps {
133
163
  * }
134
164
  * ```
135
165
  */
136
- export declare function LoadingError(props: FormErrorProps): import("react").ReactNode;
166
+ export declare function LoadingError(props: FormErrorProps): React.ReactNode;
137
167
  /**
138
168
  * Props for Form Submit Error headless component
139
169
  */
@@ -175,7 +205,7 @@ export interface FormSubmitErrorRenderProps {
175
205
  * }
176
206
  * ```
177
207
  */
178
- export declare function Error(props: FormSubmitErrorProps): import("react").ReactNode;
208
+ export declare function Error(props: FormSubmitErrorProps): React.ReactNode;
179
209
  /**
180
210
  * Props for Form Submitted headless component
181
211
  */
@@ -218,7 +248,7 @@ export interface FormSubmittedRenderProps {
218
248
  * }
219
249
  * ```
220
250
  */
221
- export declare function Submitted(props: FormSubmittedProps): import("react").ReactNode;
251
+ export declare function Submitted(props: FormSubmittedProps): React.ReactNode;
222
252
  /**
223
253
  * Render props for Fields component
224
254
  */
@@ -269,7 +299,7 @@ export interface FieldsProps {
269
299
  * }
270
300
  * ```
271
301
  */
272
- export declare function Fields(props: FieldsProps): import("react").ReactNode;
302
+ export declare function Fields(props: FieldsProps): React.ReactNode;
273
303
  /**
274
304
  * Form view interface containing field definitions
275
305
  */
@@ -342,4 +372,4 @@ export interface FieldProps {
342
372
  * }
343
373
  * ```
344
374
  */
345
- export declare function Field(props: FieldProps): import("react").ReactNode;
375
+ export declare function Field(props: FieldProps): React.ReactNode;
@@ -1,5 +1,9 @@
1
1
  "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
2
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.useFormRef = useFormRef;
3
7
  exports.Root = Root;
4
8
  exports.Loading = Loading;
5
9
  exports.LoadingError = LoadingError;
@@ -8,11 +12,22 @@ exports.Submitted = Submitted;
8
12
  exports.Fields = Fields;
9
13
  exports.Field = Field;
10
14
  const jsx_runtime_1 = require("react/jsx-runtime");
15
+ const react_1 = __importDefault(require("react"));
11
16
  const services_manager_react_1 = require("@wix/services-manager-react");
12
17
  const services_manager_1 = require("@wix/services-manager");
13
18
  const form_service_js_1 = require("../../services/form-service.js");
14
19
  const utils_js_1 = require("../utils.js");
15
20
  const DEFAULT_SUCCESS_MESSAGE = 'Your form has been submitted successfully.';
21
+ /**
22
+ * Context for passing form ref from Root to Fields
23
+ */
24
+ const FormRefContext = react_1.default.createContext(undefined);
25
+ /**
26
+ * Hook to access the form ref from context
27
+ */
28
+ function useFormRef() {
29
+ return react_1.default.useContext(FormRefContext);
30
+ }
16
31
  /**
17
32
  * Root component that provides the Form service context to its children.
18
33
  * This component sets up the necessary services for rendering and managing form data.
@@ -21,7 +36,9 @@ const DEFAULT_SUCCESS_MESSAGE = 'Your form has been submitted successfully.';
21
36
  * @component
22
37
  * @param {RootProps} props - Component props
23
38
  * @param {React.ReactNode} props.children - Child components that will have access to form context
24
- * @param {FormServiceConfig} props.formServiceConfig - Configuration object containing form data
39
+ * @param {FormServiceConfig} props.formServiceConfig - Configuration object containing form data. Supports two patterns:
40
+ * - Pre-loaded form data: `{ form: Form, onSubmit?: Function, addressTemplates?: any[] }`
41
+ * - Lazy loading: `{ formId: string, namespace?: string, additionalMetadata?: Record<string, string | string[]>, onSubmit?: Function }`
25
42
  * @example
26
43
  * ```tsx
27
44
  * import { Form } from '@wix/headless-forms/react';
@@ -56,10 +73,31 @@ const DEFAULT_SUCCESS_MESSAGE = 'Your form has been submitted successfully.';
56
73
  * </Form.Root>
57
74
  * );
58
75
  * }
76
+ *
77
+ * // Pattern 3: With namespace and additional metadata (for bookings, etc.)
78
+ * function BookingFormPage({ formId }) {
79
+ * return (
80
+ * <Form.Root
81
+ * formServiceConfig={{
82
+ * formId,
83
+ * namespace: 'wix.bookings.form',
84
+ * additionalMetadata: { serviceId: ['service-123'] },
85
+ * }}
86
+ * >
87
+ * <Form.Loading>
88
+ * {({ isLoading }) => isLoading ? <div>Loading form...</div> : null}
89
+ * </Form.Loading>
90
+ * <Form.LoadingError>
91
+ * {({ error, hasError }) => hasError ? <div>{error}</div> : null}
92
+ * </Form.LoadingError>
93
+ * <Form.Fields fieldMap={FIELD_MAP} />
94
+ * </Form.Root>
95
+ * );
96
+ * }
59
97
  * ```
60
98
  */
61
- function Root({ formServiceConfig, children, }) {
62
- return ((0, jsx_runtime_1.jsx)(services_manager_react_1.WixServices, { servicesMap: (0, services_manager_1.createServicesMap)().addService(form_service_js_1.FormServiceDefinition, form_service_js_1.FormService, formServiceConfig), children: children }));
99
+ function Root({ formServiceConfig, formRef, children, }) {
100
+ return ((0, jsx_runtime_1.jsx)(services_manager_react_1.WixServices, { servicesMap: (0, services_manager_1.createServicesMap)().addService(form_service_js_1.FormServiceDefinition, form_service_js_1.FormService, formServiceConfig), children: (0, jsx_runtime_1.jsx)(FormRefContext.Provider, { value: formRef, children: children }) }));
63
101
  }
64
102
  /**
65
103
  * Headless component for form loading state access
@@ -1,5 +1,5 @@
1
- import { type CheckboxGroupProps, type CheckboxProps, type PhoneInputProps, type DateInputProps, type DatePickerProps, type DateTimeInputProps, type DropdownProps, type FileUploadProps, type MultilineAddressProps, type NumberInputProps, type RadioGroupProps, type RatingInputProps, type RichTextProps, type SignatureProps, type SubmitButtonProps, type TagsProps, type TextAreaProps, type TextInputProps, type TimeInputProps, type ProductListProps, type FixedPaymentProps, type PaymentInputProps, type DonationProps, type AppointmentProps, type ImageChoiceProps } from '@wix/form-public';
2
- export type { CheckboxGroupProps, CheckboxProps, PhoneInputProps, DateInputProps, DatePickerProps, DateTimeInputProps, DropdownProps, FileUploadProps, MultilineAddressProps, NumberInputProps, RadioGroupProps, RatingInputProps, RichTextProps, SignatureProps, SubmitButtonProps, TagsProps, TextAreaProps, TextInputProps, TimeInputProps, ProductListProps, FixedPaymentProps, PaymentInputProps, DonationProps, AppointmentProps, ImageChoiceProps, };
1
+ import { type CheckboxGroupProps, type CheckboxProps, type PhoneInputProps, type DateInputProps, type DatePickerProps, type DateTimeInputProps, type DropdownProps, type FileUploadProps, type MultilineAddressProps, type NumberInputProps, type RadioGroupProps, type RatingInputProps, type RichTextProps, type SignatureProps, type SubmitButtonProps, type TagsProps, type TextAreaProps, type TextInputProps, type TimeInputProps, type ProductListProps, type FixedPaymentProps, type PaymentInputProps, type DonationProps, type AppointmentProps, type ImageChoiceProps, type UseFormProps, type LoginBarProps } from '@wix/form-public';
2
+ export type { CheckboxGroupProps, CheckboxProps, PhoneInputProps, DateInputProps, DatePickerProps, DateTimeInputProps, DropdownProps, FileUploadProps, MultilineAddressProps, NumberInputProps, RadioGroupProps, RatingInputProps, RichTextProps, SignatureProps, SubmitButtonProps, TagsProps, TextAreaProps, TextInputProps, TimeInputProps, ProductListProps, FixedPaymentProps, PaymentInputProps, DonationProps, AppointmentProps, ImageChoiceProps, UseFormProps, LoginBarProps, };
3
3
  export type FormValues = Record<string, any>;
4
4
  export interface UploadFileParams {
5
5
  file: File;
@@ -5,8 +5,8 @@ exports.loadFormServiceConfig = loadFormServiceConfig;
5
5
  const forms_1 = require("@wix/forms");
6
6
  const services_definitions_1 = require("@wix/services-definitions");
7
7
  const signals_1 = require("@wix/services-definitions/core-services/signals");
8
- const essentials_1 = require("@wix/essentials");
9
8
  const address_forms_js_1 = require("./utils/address-forms.js");
9
+ const auto_sdk_forms_forms_1 = require("@wix/auto_sdk_forms_forms");
10
10
  /**
11
11
  * Service definition for the Form service.
12
12
  * This defines the contract that the FormService must implement.
@@ -151,41 +151,18 @@ exports.FormService = services_definitions_1.implementService.withConfig()(expor
151
151
  handleForm,
152
152
  };
153
153
  });
154
- function buildFormFetchQueryParams({ id, namespace, additionalMetadata, }) {
155
- const params = new URLSearchParams();
156
- params.append('formId', id);
157
- if (namespace) {
158
- params.append('namespace', namespace);
159
- }
160
- if (additionalMetadata) {
161
- Object.entries(additionalMetadata).forEach(([key, value]) => {
162
- if (Array.isArray(value)) {
163
- value.forEach((v) => params.append(key, v));
164
- }
165
- else {
166
- params.append(key, value);
167
- }
168
- });
169
- }
170
- return params;
171
- }
172
- async function fetchForm({ id, namespace, additionalMetadata, }) {
154
+ async function fetchForm({ id, namespace = 'wix.form_app.form', additionalMetadata, }) {
173
155
  try {
174
- const params = buildFormFetchQueryParams({
175
- id,
176
- namespace,
156
+ const response = await forms_1.forms.listForms(namespace, {
177
157
  additionalMetadata,
158
+ formIds: [id],
159
+ fieldsets: [auto_sdk_forms_forms_1.Fieldset.NESTED_FORMS],
178
160
  });
179
- const url = `https://www.wixapis.com/form-schema-service/v4/forms/${id}?${params.toString()}`;
180
- const response = await essentials_1.httpClient.fetchWithAuth(url);
181
- if (!response.ok) {
182
- throw new Error(`Failed to fetch form: ${response.status} ${response.statusText}`);
183
- }
184
- const data = await response.json();
185
- if (data && data.form) {
186
- return data.form;
161
+ const form = response.forms?.[0];
162
+ if (!form) {
163
+ throw new Error('Form not found');
187
164
  }
188
- throw new Error('Invalid response format from Forms API');
165
+ return form;
189
166
  }
190
167
  catch (err) {
191
168
  console.error('Failed to load form:', id, err);
@@ -1,6 +1,6 @@
1
1
  import React from 'react';
2
2
  import { type FormError } from '@wix/form-public';
3
- import { type CheckboxGroupProps, type CheckboxProps, type PhoneInputProps, type DateInputProps, type DatePickerProps, type DateTimeInputProps, type DropdownProps, type FileUploadProps, type MultilineAddressProps, type NumberInputProps, type RadioGroupProps, type RatingInputProps, type RichTextProps, type SignatureProps, type SubmitButtonProps, type TagsProps, type TextAreaProps, type TextInputProps, type TimeInputProps, type ProductListProps, type FixedPaymentProps, type PaymentInputProps, type DonationProps, type AppointmentProps, type ImageChoiceProps } from './types.js';
3
+ import { type CheckboxGroupProps, type CheckboxProps, type PhoneInputProps, type DateInputProps, type DatePickerProps, type DateTimeInputProps, type DropdownProps, type FileUploadProps, type MultilineAddressProps, type NumberInputProps, type RadioGroupProps, type RatingInputProps, type RichTextProps, type SignatureProps, type SubmitButtonProps, type TagsProps, type TextAreaProps, type TextInputProps, type TimeInputProps, type ProductListProps, type FixedPaymentProps, type PaymentInputProps, type DonationProps, type AppointmentProps, type ImageChoiceProps, type LoginBarProps } from './types.js';
4
4
  import { type FormServiceConfig } from '../services/form-service.js';
5
5
  /**
6
6
  * Props for the Form root component following the documented API
@@ -22,7 +22,9 @@ export interface RootProps {
22
22
  * @component
23
23
  * @param {RootProps} props - The component props
24
24
  * @param {React.ReactNode} props.children - Child components that will have access to form context
25
- * @param {FormServiceConfig} props.formServiceConfig - Form service configuration object
25
+ * @param {FormServiceConfig} props.formServiceConfig - Form service configuration object. Supports two patterns:
26
+ * - Pre-loaded form data: `{ form: Form, onSubmit?: Function, addressTemplates?: any[] }`
27
+ * - Lazy loading: `{ formId: string, namespace?: string, additionalMetadata?: Record<string, string | string[]>, onSubmit?: Function }`
26
28
  * @param {boolean} [props.asChild] - Whether to render as a child component
27
29
  * @param {string} [props.className] - CSS classes to apply to the root element
28
30
  * @example
@@ -62,6 +64,25 @@ export interface RootProps {
62
64
  * </Form.Root>
63
65
  * );
64
66
  * }
67
+ *
68
+ * // Pattern 3: With namespace and additional metadata (for bookings, etc.)
69
+ * function BookingFormPage({ formId }) {
70
+ * return (
71
+ * <Form.Root
72
+ * formServiceConfig={{
73
+ * formId,
74
+ * namespace: 'wix.bookings.form',
75
+ * additionalMetadata: { serviceId: ['service-123'] },
76
+ * }}
77
+ * >
78
+ * <Form.Loading className="flex justify-center p-4" />
79
+ * <Form.LoadingError className="text-destructive px-4 py-3 rounded mb-4" />
80
+ * <Form.Fields fieldMap={FIELD_MAP} />
81
+ * <Form.Error className="text-destructive p-4 rounded-lg mb-4" />
82
+ * <Form.Submitted className="text-green-500 p-4 rounded-lg mb-4" />
83
+ * </Form.Root>
84
+ * );
85
+ * }
65
86
  * ```
66
87
  */
67
88
  export declare const Root: React.ForwardRefExoticComponent<RootProps & React.RefAttributes<HTMLDivElement>>;
@@ -399,6 +420,7 @@ export interface FieldMap {
399
420
  DONATION: React.ComponentType<DonationProps>;
400
421
  APPOINTMENT: React.ComponentType<AppointmentProps>;
401
422
  IMAGE_CHOICE: React.ComponentType<ImageChoiceProps>;
423
+ LOGIN_BAR: React.ComponentType<LoginBarProps>;
402
424
  }
403
425
  /**
404
426
  * Props for the Form Fields component.
@@ -3,7 +3,7 @@ import React, { useState, useCallback } from 'react';
3
3
  import { AsChildSlot } from '@wix/headless-utils/react';
4
4
  import { useForm, FormProvider, UniqueFieldSuffixContextProvider, } from '@wix/form-public';
5
5
  import { i18n } from '@wix/essentials';
6
- import { Root as CoreRoot, Loading as CoreLoading, LoadingError as CoreLoadingError, Error as CoreError, Submitted as CoreSubmitted, Fields as CoreFields, Field as CoreField, } from './core/Form.js';
6
+ import { Root as CoreRoot, Loading as CoreLoading, LoadingError as CoreLoadingError, Error as CoreError, Submitted as CoreSubmitted, Fields as CoreFields, Field as CoreField, useFormRef, } from './core/Form.js';
7
7
  import { FieldContext, useFieldContext, } from './context/FieldContext.js';
8
8
  import { FieldLayoutProvider, useFieldLayout, } from './context/FieldLayoutContext.js';
9
9
  import { getUploadUrl, uploadFile } from '../services/utils';
@@ -29,7 +29,9 @@ var TestIds;
29
29
  * @component
30
30
  * @param {RootProps} props - The component props
31
31
  * @param {React.ReactNode} props.children - Child components that will have access to form context
32
- * @param {FormServiceConfig} props.formServiceConfig - Form service configuration object
32
+ * @param {FormServiceConfig} props.formServiceConfig - Form service configuration object. Supports two patterns:
33
+ * - Pre-loaded form data: `{ form: Form, onSubmit?: Function, addressTemplates?: any[] }`
34
+ * - Lazy loading: `{ formId: string, namespace?: string, additionalMetadata?: Record<string, string | string[]>, onSubmit?: Function }`
33
35
  * @param {boolean} [props.asChild] - Whether to render as a child component
34
36
  * @param {string} [props.className] - CSS classes to apply to the root element
35
37
  * @example
@@ -69,11 +71,30 @@ var TestIds;
69
71
  * </Form.Root>
70
72
  * );
71
73
  * }
74
+ *
75
+ * // Pattern 3: With namespace and additional metadata (for bookings, etc.)
76
+ * function BookingFormPage({ formId }) {
77
+ * return (
78
+ * <Form.Root
79
+ * formServiceConfig={{
80
+ * formId,
81
+ * namespace: 'wix.bookings.form',
82
+ * additionalMetadata: { serviceId: ['service-123'] },
83
+ * }}
84
+ * >
85
+ * <Form.Loading className="flex justify-center p-4" />
86
+ * <Form.LoadingError className="text-destructive px-4 py-3 rounded mb-4" />
87
+ * <Form.Fields fieldMap={FIELD_MAP} />
88
+ * <Form.Error className="text-destructive p-4 rounded-lg mb-4" />
89
+ * <Form.Submitted className="text-green-500 p-4 rounded-lg mb-4" />
90
+ * </Form.Root>
91
+ * );
92
+ * }
72
93
  * ```
73
94
  */
74
95
  export const Root = React.forwardRef((props, ref) => {
75
96
  const { children, formServiceConfig, asChild, ...otherProps } = props;
76
- return (_jsx(CoreRoot, { formServiceConfig: formServiceConfig, children: _jsx(RootContent, { asChild: asChild, ref: ref, ...otherProps, children: children }) }));
97
+ return (_jsx(CoreRoot, { formServiceConfig: formServiceConfig, formRef: ref, children: _jsx(RootContent, { asChild: asChild, ref: ref, ...otherProps, children: children }) }));
77
98
  });
78
99
  /**
79
100
  * Internal component to handle the Root content with service access.
@@ -492,16 +513,17 @@ export const Fields = React.forwardRef((props, ref) => {
492
513
  const [formErrors, setFormErrors] = useState([]);
493
514
  const currentLocale = i18n.getLocale();
494
515
  const currentLanguage = i18n.getLanguage();
516
+ const formRef = useFormRef();
495
517
  const handleFormValidate = useCallback((errors) => {
496
518
  setFormErrors(errors);
497
519
  }, []);
498
520
  return (_jsx(CoreFields, { children: ({ form, formValues, submitForm, handleForm, addressTemplates }) => {
499
521
  if (!form)
500
522
  return null;
501
- return (_jsx("div", { ref: ref, children: _jsx(FormProvider, { currency: 'USD', locale: currentLanguage, regionalFormat: currentLocale, addressTemplates: addressTemplates, children: _jsx(UniqueFieldSuffixContextProvider, { parentId: form._id ?? '', children: _jsx(FieldsWithForm, { form: form, values: formValues, onChange: handleForm, errors: formErrors, onValidate: handleFormValidate, fields: props.fieldMap, submitForm: submitForm, rowGapClassname: props.rowGapClassname, columnGapClassname: props.columnGapClassname }) }) }) }));
523
+ return (_jsx("div", { ref: ref, children: _jsx(FormProvider, { currency: 'USD', locale: currentLanguage, regionalFormat: currentLocale, addressTemplates: addressTemplates, children: _jsx(UniqueFieldSuffixContextProvider, { parentId: form._id ?? '', children: _jsx(FieldsWithForm, { form: form, values: formValues, onChange: handleForm, errors: formErrors, onValidate: handleFormValidate, fields: props.fieldMap, submitForm: submitForm, rowGapClassname: props.rowGapClassname, columnGapClassname: props.columnGapClassname, formRef: formRef }) }) }) }));
502
524
  } }));
503
525
  });
504
- const FieldsWithForm = ({ form, submitForm, values, onChange, errors, onValidate, fields: fieldMap, rowGapClassname, columnGapClassname, }) => {
526
+ const FieldsWithForm = ({ form, submitForm, values, onChange, errors, onValidate, fields: fieldMap, rowGapClassname, columnGapClassname, formRef, }) => {
505
527
  const coreUploadFile = async ({ file, formId, }) => {
506
528
  const uploadUrl = await getUploadUrl(formId, file);
507
529
  if (uploadUrl === undefined) {
@@ -524,6 +546,7 @@ const FieldsWithForm = ({ form, submitForm, values, onChange, errors, onValidate
524
546
  submitForm,
525
547
  uploadFile: coreUploadFile,
526
548
  fieldMap,
549
+ forwardedRef: formRef,
527
550
  });
528
551
  if (!formData)
529
552
  return null;
@@ -1,12 +1,19 @@
1
+ import React from 'react';
1
2
  import { forms } from '@wix/forms';
2
3
  import { FormServiceConfig } from '../../services/form-service.js';
3
4
  import { FormValues } from '../types.js';
5
+ /**
6
+ * Hook to access the form ref from context
7
+ */
8
+ export declare function useFormRef(): React.Ref<any> | undefined;
4
9
  /**
5
10
  * Props for Root headless component
6
11
  */
7
12
  export interface RootProps {
8
13
  children: React.ReactNode;
9
14
  formServiceConfig: FormServiceConfig;
15
+ /** Optional ref to access form methods imperatively */
16
+ formRef?: React.Ref<any>;
10
17
  }
11
18
  /**
12
19
  * Root component that provides the Form service context to its children.
@@ -16,7 +23,9 @@ export interface RootProps {
16
23
  * @component
17
24
  * @param {RootProps} props - Component props
18
25
  * @param {React.ReactNode} props.children - Child components that will have access to form context
19
- * @param {FormServiceConfig} props.formServiceConfig - Configuration object containing form data
26
+ * @param {FormServiceConfig} props.formServiceConfig - Configuration object containing form data. Supports two patterns:
27
+ * - Pre-loaded form data: `{ form: Form, onSubmit?: Function, addressTemplates?: any[] }`
28
+ * - Lazy loading: `{ formId: string, namespace?: string, additionalMetadata?: Record<string, string | string[]>, onSubmit?: Function }`
20
29
  * @example
21
30
  * ```tsx
22
31
  * import { Form } from '@wix/headless-forms/react';
@@ -51,9 +60,30 @@ export interface RootProps {
51
60
  * </Form.Root>
52
61
  * );
53
62
  * }
63
+ *
64
+ * // Pattern 3: With namespace and additional metadata (for bookings, etc.)
65
+ * function BookingFormPage({ formId }) {
66
+ * return (
67
+ * <Form.Root
68
+ * formServiceConfig={{
69
+ * formId,
70
+ * namespace: 'wix.bookings.form',
71
+ * additionalMetadata: { serviceId: ['service-123'] },
72
+ * }}
73
+ * >
74
+ * <Form.Loading>
75
+ * {({ isLoading }) => isLoading ? <div>Loading form...</div> : null}
76
+ * </Form.Loading>
77
+ * <Form.LoadingError>
78
+ * {({ error, hasError }) => hasError ? <div>{error}</div> : null}
79
+ * </Form.LoadingError>
80
+ * <Form.Fields fieldMap={FIELD_MAP} />
81
+ * </Form.Root>
82
+ * );
83
+ * }
54
84
  * ```
55
85
  */
56
- export declare function Root({ formServiceConfig, children, }: RootProps): React.ReactNode;
86
+ export declare function Root({ formServiceConfig, formRef, children, }: RootProps): React.ReactNode;
57
87
  /**
58
88
  * Props for FormLoading headless component
59
89
  */
@@ -91,7 +121,7 @@ export interface FormLoadingRenderProps {
91
121
  * }
92
122
  * ```
93
123
  */
94
- export declare function Loading(props: FormLoadingProps): import("react").ReactNode;
124
+ export declare function Loading(props: FormLoadingProps): React.ReactNode;
95
125
  /**
96
126
  * Props for FormError headless component
97
127
  */
@@ -133,7 +163,7 @@ export interface FormErrorRenderProps {
133
163
  * }
134
164
  * ```
135
165
  */
136
- export declare function LoadingError(props: FormErrorProps): import("react").ReactNode;
166
+ export declare function LoadingError(props: FormErrorProps): React.ReactNode;
137
167
  /**
138
168
  * Props for Form Submit Error headless component
139
169
  */
@@ -175,7 +205,7 @@ export interface FormSubmitErrorRenderProps {
175
205
  * }
176
206
  * ```
177
207
  */
178
- export declare function Error(props: FormSubmitErrorProps): import("react").ReactNode;
208
+ export declare function Error(props: FormSubmitErrorProps): React.ReactNode;
179
209
  /**
180
210
  * Props for Form Submitted headless component
181
211
  */
@@ -218,7 +248,7 @@ export interface FormSubmittedRenderProps {
218
248
  * }
219
249
  * ```
220
250
  */
221
- export declare function Submitted(props: FormSubmittedProps): import("react").ReactNode;
251
+ export declare function Submitted(props: FormSubmittedProps): React.ReactNode;
222
252
  /**
223
253
  * Render props for Fields component
224
254
  */
@@ -269,7 +299,7 @@ export interface FieldsProps {
269
299
  * }
270
300
  * ```
271
301
  */
272
- export declare function Fields(props: FieldsProps): import("react").ReactNode;
302
+ export declare function Fields(props: FieldsProps): React.ReactNode;
273
303
  /**
274
304
  * Form view interface containing field definitions
275
305
  */
@@ -342,4 +372,4 @@ export interface FieldProps {
342
372
  * }
343
373
  * ```
344
374
  */
345
- export declare function Field(props: FieldProps): import("react").ReactNode;
375
+ export declare function Field(props: FieldProps): React.ReactNode;
@@ -1,9 +1,20 @@
1
1
  import { jsx as _jsx } from "react/jsx-runtime";
2
+ import React from 'react';
2
3
  import { useService, WixServices } from '@wix/services-manager-react';
3
4
  import { createServicesMap } from '@wix/services-manager';
4
5
  import { FormServiceDefinition, FormService, } from '../../services/form-service.js';
5
6
  import { calculateGridStyles } from '../utils.js';
6
7
  const DEFAULT_SUCCESS_MESSAGE = 'Your form has been submitted successfully.';
8
+ /**
9
+ * Context for passing form ref from Root to Fields
10
+ */
11
+ const FormRefContext = React.createContext(undefined);
12
+ /**
13
+ * Hook to access the form ref from context
14
+ */
15
+ export function useFormRef() {
16
+ return React.useContext(FormRefContext);
17
+ }
7
18
  /**
8
19
  * Root component that provides the Form service context to its children.
9
20
  * This component sets up the necessary services for rendering and managing form data.
@@ -12,7 +23,9 @@ const DEFAULT_SUCCESS_MESSAGE = 'Your form has been submitted successfully.';
12
23
  * @component
13
24
  * @param {RootProps} props - Component props
14
25
  * @param {React.ReactNode} props.children - Child components that will have access to form context
15
- * @param {FormServiceConfig} props.formServiceConfig - Configuration object containing form data
26
+ * @param {FormServiceConfig} props.formServiceConfig - Configuration object containing form data. Supports two patterns:
27
+ * - Pre-loaded form data: `{ form: Form, onSubmit?: Function, addressTemplates?: any[] }`
28
+ * - Lazy loading: `{ formId: string, namespace?: string, additionalMetadata?: Record<string, string | string[]>, onSubmit?: Function }`
16
29
  * @example
17
30
  * ```tsx
18
31
  * import { Form } from '@wix/headless-forms/react';
@@ -47,10 +60,31 @@ const DEFAULT_SUCCESS_MESSAGE = 'Your form has been submitted successfully.';
47
60
  * </Form.Root>
48
61
  * );
49
62
  * }
63
+ *
64
+ * // Pattern 3: With namespace and additional metadata (for bookings, etc.)
65
+ * function BookingFormPage({ formId }) {
66
+ * return (
67
+ * <Form.Root
68
+ * formServiceConfig={{
69
+ * formId,
70
+ * namespace: 'wix.bookings.form',
71
+ * additionalMetadata: { serviceId: ['service-123'] },
72
+ * }}
73
+ * >
74
+ * <Form.Loading>
75
+ * {({ isLoading }) => isLoading ? <div>Loading form...</div> : null}
76
+ * </Form.Loading>
77
+ * <Form.LoadingError>
78
+ * {({ error, hasError }) => hasError ? <div>{error}</div> : null}
79
+ * </Form.LoadingError>
80
+ * <Form.Fields fieldMap={FIELD_MAP} />
81
+ * </Form.Root>
82
+ * );
83
+ * }
50
84
  * ```
51
85
  */
52
- export function Root({ formServiceConfig, children, }) {
53
- return (_jsx(WixServices, { servicesMap: createServicesMap().addService(FormServiceDefinition, FormService, formServiceConfig), children: children }));
86
+ export function Root({ formServiceConfig, formRef, children, }) {
87
+ return (_jsx(WixServices, { servicesMap: createServicesMap().addService(FormServiceDefinition, FormService, formServiceConfig), children: _jsx(FormRefContext.Provider, { value: formRef, children: children }) }));
54
88
  }
55
89
  /**
56
90
  * Headless component for form loading state access
@@ -1,5 +1,5 @@
1
- import { type CheckboxGroupProps, type CheckboxProps, type PhoneInputProps, type DateInputProps, type DatePickerProps, type DateTimeInputProps, type DropdownProps, type FileUploadProps, type MultilineAddressProps, type NumberInputProps, type RadioGroupProps, type RatingInputProps, type RichTextProps, type SignatureProps, type SubmitButtonProps, type TagsProps, type TextAreaProps, type TextInputProps, type TimeInputProps, type ProductListProps, type FixedPaymentProps, type PaymentInputProps, type DonationProps, type AppointmentProps, type ImageChoiceProps } from '@wix/form-public';
2
- export type { CheckboxGroupProps, CheckboxProps, PhoneInputProps, DateInputProps, DatePickerProps, DateTimeInputProps, DropdownProps, FileUploadProps, MultilineAddressProps, NumberInputProps, RadioGroupProps, RatingInputProps, RichTextProps, SignatureProps, SubmitButtonProps, TagsProps, TextAreaProps, TextInputProps, TimeInputProps, ProductListProps, FixedPaymentProps, PaymentInputProps, DonationProps, AppointmentProps, ImageChoiceProps, };
1
+ import { type CheckboxGroupProps, type CheckboxProps, type PhoneInputProps, type DateInputProps, type DatePickerProps, type DateTimeInputProps, type DropdownProps, type FileUploadProps, type MultilineAddressProps, type NumberInputProps, type RadioGroupProps, type RatingInputProps, type RichTextProps, type SignatureProps, type SubmitButtonProps, type TagsProps, type TextAreaProps, type TextInputProps, type TimeInputProps, type ProductListProps, type FixedPaymentProps, type PaymentInputProps, type DonationProps, type AppointmentProps, type ImageChoiceProps, type UseFormProps, type LoginBarProps } from '@wix/form-public';
2
+ export type { CheckboxGroupProps, CheckboxProps, PhoneInputProps, DateInputProps, DatePickerProps, DateTimeInputProps, DropdownProps, FileUploadProps, MultilineAddressProps, NumberInputProps, RadioGroupProps, RatingInputProps, RichTextProps, SignatureProps, SubmitButtonProps, TagsProps, TextAreaProps, TextInputProps, TimeInputProps, ProductListProps, FixedPaymentProps, PaymentInputProps, DonationProps, AppointmentProps, ImageChoiceProps, UseFormProps, LoginBarProps, };
3
3
  export type FormValues = Record<string, any>;
4
4
  export interface UploadFileParams {
5
5
  file: File;
@@ -1,8 +1,8 @@
1
- import { submissions } from '@wix/forms';
1
+ import { forms, submissions } from '@wix/forms';
2
2
  import { defineService, implementService } from '@wix/services-definitions';
3
3
  import { SignalsServiceDefinition, } from '@wix/services-definitions/core-services/signals';
4
- import { httpClient } from '@wix/essentials';
5
4
  import { fetchAddressForms, hasMultilineAddressField, } from './utils/address-forms.js';
5
+ import { Fieldset } from '@wix/auto_sdk_forms_forms';
6
6
  /**
7
7
  * Service definition for the Form service.
8
8
  * This defines the contract that the FormService must implement.
@@ -147,41 +147,18 @@ export const FormService = implementService.withConfig()(FormServiceDefinition,
147
147
  handleForm,
148
148
  };
149
149
  });
150
- function buildFormFetchQueryParams({ id, namespace, additionalMetadata, }) {
151
- const params = new URLSearchParams();
152
- params.append('formId', id);
153
- if (namespace) {
154
- params.append('namespace', namespace);
155
- }
156
- if (additionalMetadata) {
157
- Object.entries(additionalMetadata).forEach(([key, value]) => {
158
- if (Array.isArray(value)) {
159
- value.forEach((v) => params.append(key, v));
160
- }
161
- else {
162
- params.append(key, value);
163
- }
164
- });
165
- }
166
- return params;
167
- }
168
- async function fetchForm({ id, namespace, additionalMetadata, }) {
150
+ async function fetchForm({ id, namespace = 'wix.form_app.form', additionalMetadata, }) {
169
151
  try {
170
- const params = buildFormFetchQueryParams({
171
- id,
172
- namespace,
152
+ const response = await forms.listForms(namespace, {
173
153
  additionalMetadata,
154
+ formIds: [id],
155
+ fieldsets: [Fieldset.NESTED_FORMS],
174
156
  });
175
- const url = `https://www.wixapis.com/form-schema-service/v4/forms/${id}?${params.toString()}`;
176
- const response = await httpClient.fetchWithAuth(url);
177
- if (!response.ok) {
178
- throw new Error(`Failed to fetch form: ${response.status} ${response.statusText}`);
179
- }
180
- const data = await response.json();
181
- if (data && data.form) {
182
- return data.form;
157
+ const form = response.forms?.[0];
158
+ if (!form) {
159
+ throw new Error('Form not found');
183
160
  }
184
- throw new Error('Invalid response format from Forms API');
161
+ return form;
185
162
  }
186
163
  catch (err) {
187
164
  console.error('Failed to load form:', id, err);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@wix/headless-forms",
3
- "version": "0.0.21",
3
+ "version": "0.0.23",
4
4
  "license": "MIT",
5
5
  "type": "module",
6
6
  "scripts": {
@@ -42,8 +42,8 @@
42
42
  "vitest": "^3.1.4"
43
43
  },
44
44
  "dependencies": {
45
- "@wix/form-public": "^0.95.0",
46
- "@wix/forms": "^1.0.331",
45
+ "@wix/form-public": "^0.104.0",
46
+ "@wix/forms": "^1.0.373",
47
47
  "@wix/headless-utils": "0.0.8",
48
48
  "@wix/services-definitions": "^0.1.4",
49
49
  "@wix/services-manager-react": "^0.1.26",
@@ -59,5 +59,5 @@
59
59
  "groupId": "com.wixpress.headless-components"
60
60
  }
61
61
  },
62
- "falconPackageHash": "7a802b3af894bd379d396ecadf0577e0d20335ee486354273b550919"
62
+ "falconPackageHash": "6d90b5a274c89f69fb6007bfac926468be779780b40000231b716ec3"
63
63
  }