@wix/headless-forms 0.0.2 → 0.0.3
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/README.md +46 -0
- package/cjs/dist/react/Form.d.ts +3 -67
- package/cjs/dist/react/Form.js +25 -86
- package/cjs/dist/react/core/Form.d.ts +49 -3
- package/cjs/dist/react/core/Form.js +51 -19
- package/cjs/dist/services/form-service.d.ts +51 -150
- package/cjs/dist/services/form-service.js +65 -110
- package/dist/react/Form.d.ts +3 -67
- package/dist/react/Form.js +25 -86
- package/dist/react/core/Form.d.ts +49 -3
- package/dist/react/core/Form.js +50 -19
- package/dist/services/form-service.d.ts +51 -150
- package/dist/services/form-service.js +65 -110
- package/package.json +1 -1
package/dist/react/Form.js
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
-
import React, {
|
|
2
|
+
import React, { useState, useCallback } from 'react';
|
|
3
3
|
import { AsChildSlot } from '@wix/headless-utils/react';
|
|
4
|
-
import { useService } from '@wix/services-manager-react';
|
|
5
4
|
import { Form as FormViewer, } from '@wix/form-public';
|
|
6
|
-
import {
|
|
7
|
-
import * as CoreForm from './core/Form';
|
|
5
|
+
import { Root as CoreRoot, Loading as CoreLoading, LoadingError as CoreLoadingError, Error as CoreError, Submitted as CoreSubmitted, Fields as CoreFields, } from './core/Form';
|
|
8
6
|
var TestIds;
|
|
9
7
|
(function (TestIds) {
|
|
10
8
|
TestIds["formRoot"] = "form-root";
|
|
9
|
+
TestIds["form"] = "form";
|
|
10
|
+
TestIds["formLoading"] = "form-loading";
|
|
11
11
|
TestIds["formLoadingError"] = "form-loading-error";
|
|
12
12
|
TestIds["formError"] = "form-error";
|
|
13
13
|
TestIds["formSubmitted"] = "form-submitted";
|
|
@@ -21,6 +21,7 @@ var TestIds;
|
|
|
21
21
|
* @param {RootProps} props - The component props
|
|
22
22
|
* @param {React.ReactNode} props.children - Child components that will have access to form context
|
|
23
23
|
* @param {FormServiceConfig} props.formServiceConfig - Form service configuration object
|
|
24
|
+
* @param {boolean} [props.asChild] - Whether to render as a child component
|
|
24
25
|
* @param {string} [props.className] - CSS classes to apply to the root element
|
|
25
26
|
* @example
|
|
26
27
|
* ```tsx
|
|
@@ -63,7 +64,7 @@ var TestIds;
|
|
|
63
64
|
*/
|
|
64
65
|
export const Root = React.forwardRef((props, ref) => {
|
|
65
66
|
const { children, formServiceConfig, asChild, ...otherProps } = props;
|
|
66
|
-
return (_jsx(
|
|
67
|
+
return (_jsx(CoreRoot, { formServiceConfig: formServiceConfig, children: _jsx(RootContent, { asChild: asChild, ref: ref, ...otherProps, children: children }) }));
|
|
67
68
|
});
|
|
68
69
|
/**
|
|
69
70
|
* Internal component to handle the Root content with service access.
|
|
@@ -127,10 +128,10 @@ const RootContent = React.forwardRef((props, ref) => {
|
|
|
127
128
|
*/
|
|
128
129
|
export const Loading = React.forwardRef((props, ref) => {
|
|
129
130
|
const { asChild, children, className, ...otherProps } = props;
|
|
130
|
-
return (_jsx(
|
|
131
|
+
return (_jsx(CoreLoading, { children: ({ isLoading }) => {
|
|
131
132
|
if (!isLoading)
|
|
132
133
|
return null;
|
|
133
|
-
return (_jsx(AsChildSlot, { ref: ref, asChild: asChild, className: className,
|
|
134
|
+
return (_jsx(AsChildSlot, { "data-testid": TestIds.formLoading, ref: ref, asChild: asChild, className: className, customElement: children, content: "Loading form...", ...otherProps, children: _jsx("div", { children: "Loading form..." }) }));
|
|
134
135
|
} }));
|
|
135
136
|
});
|
|
136
137
|
/**
|
|
@@ -184,7 +185,7 @@ export const Loading = React.forwardRef((props, ref) => {
|
|
|
184
185
|
*/
|
|
185
186
|
export const LoadingError = React.forwardRef((props, ref) => {
|
|
186
187
|
const { asChild, children, className, ...otherProps } = props;
|
|
187
|
-
return (_jsx(
|
|
188
|
+
return (_jsx(CoreLoadingError, { children: ({ error, hasError }) => {
|
|
188
189
|
if (!hasError)
|
|
189
190
|
return null;
|
|
190
191
|
const errorData = { error, hasError };
|
|
@@ -240,7 +241,7 @@ export const LoadingError = React.forwardRef((props, ref) => {
|
|
|
240
241
|
*/
|
|
241
242
|
export const Error = React.forwardRef((props, ref) => {
|
|
242
243
|
const { asChild, children, className, ...otherProps } = props;
|
|
243
|
-
return (_jsx(
|
|
244
|
+
return (_jsx(CoreError, { children: ({ error, hasError }) => {
|
|
244
245
|
if (!hasError)
|
|
245
246
|
return null;
|
|
246
247
|
const errorData = { error, hasError };
|
|
@@ -296,7 +297,7 @@ export const Error = React.forwardRef((props, ref) => {
|
|
|
296
297
|
*/
|
|
297
298
|
export const Submitted = React.forwardRef((props, ref) => {
|
|
298
299
|
const { asChild, children, className, ...otherProps } = props;
|
|
299
|
-
return (_jsx(
|
|
300
|
+
return (_jsx(CoreSubmitted, { children: ({ isSubmitted, message }) => {
|
|
300
301
|
if (!isSubmitted)
|
|
301
302
|
return null;
|
|
302
303
|
const submittedData = { isSubmitted, message };
|
|
@@ -447,14 +448,7 @@ export const Submitted = React.forwardRef((props, ref) => {
|
|
|
447
448
|
* };
|
|
448
449
|
* ```
|
|
449
450
|
*/
|
|
450
|
-
export const Fields = React.forwardRef((
|
|
451
|
-
const formService = useService(FormServiceDefinition);
|
|
452
|
-
const form = formService.form.get();
|
|
453
|
-
const _form = {
|
|
454
|
-
...form,
|
|
455
|
-
id: form?._id,
|
|
456
|
-
fields: form?.formFields?.map((field) => ({ ...field, id: field._id })),
|
|
457
|
-
};
|
|
451
|
+
export const Fields = React.forwardRef((props, ref) => {
|
|
458
452
|
const [formValues, setFormValues] = useState({});
|
|
459
453
|
const [formErrors, setFormErrors] = useState([]);
|
|
460
454
|
const handleFormChange = useCallback((values) => {
|
|
@@ -463,72 +457,17 @@ export const Fields = React.forwardRef(({ fieldMap }, ref) => {
|
|
|
463
457
|
const handleFormValidate = useCallback((errors) => {
|
|
464
458
|
setFormErrors(errors);
|
|
465
459
|
}, []);
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
460
|
+
return (_jsx(CoreFields, { children: ({ form }) => {
|
|
461
|
+
console.log('Fields form', form);
|
|
462
|
+
if (!form)
|
|
463
|
+
return null;
|
|
464
|
+
return (_jsx("div", { ref: ref, children: _jsx(FormViewer, { form: {
|
|
465
|
+
...form,
|
|
466
|
+
id: form?._id,
|
|
467
|
+
fields: form?.formFields?.map((field) => ({
|
|
468
|
+
...field,
|
|
469
|
+
id: field._id,
|
|
470
|
+
})),
|
|
471
|
+
}, values: formValues, onChange: handleFormChange, errors: formErrors, onValidate: handleFormValidate, fields: props.fieldMap }) }));
|
|
472
|
+
} }));
|
|
469
473
|
});
|
|
470
|
-
/**
|
|
471
|
-
* Main Form namespace containing all form components following the compound component pattern.
|
|
472
|
-
* Provides a headless, flexible way to render and manage forms with custom field components.
|
|
473
|
-
*
|
|
474
|
-
* @namespace Form
|
|
475
|
-
* @property {typeof Root} Root - Form root component that provides service context to all child components
|
|
476
|
-
* @property {typeof Loading} Loading - Form loading state component that displays content during form loading
|
|
477
|
-
* @property {typeof LoadingError} LoadingError - Form loading error state component for handling form loading errors
|
|
478
|
-
* @property {typeof Error} Error - Form submit error state component for handling form submission errors
|
|
479
|
-
* @property {typeof Submitted} Submitted - Form submitted state component for displaying success messages
|
|
480
|
-
* @property {typeof Fields} Fields - Form fields component for rendering form fields with custom field renderers
|
|
481
|
-
* @example
|
|
482
|
-
* ```tsx
|
|
483
|
-
* import { Form } from '@wix/headless-forms/react';
|
|
484
|
-
* import { loadFormServiceConfig } from '@wix/headless-forms/services';
|
|
485
|
-
* import { TextInput, TextArea, Checkbox } from './field-components';
|
|
486
|
-
*
|
|
487
|
-
* const FIELD_MAP = {
|
|
488
|
-
* TEXT_INPUT: TextInput,
|
|
489
|
-
* TEXT_AREA: TextArea,
|
|
490
|
-
* CHECKBOX: Checkbox,
|
|
491
|
-
* // ... other field components
|
|
492
|
-
* };
|
|
493
|
-
*
|
|
494
|
-
* // Pattern 1: Pre-loaded form data (SSR/SSG)
|
|
495
|
-
* function MyForm({ formServiceConfig }) {
|
|
496
|
-
* return (
|
|
497
|
-
* <Form.Root formServiceConfig={formServiceConfig}>
|
|
498
|
-
* <Form.Loading className="flex justify-center p-4" />
|
|
499
|
-
* <Form.LoadingError className="text-destructive px-4 py-3 rounded mb-4" />
|
|
500
|
-
* <Form.Fields fieldMap={FIELD_MAP} />
|
|
501
|
-
* <Form.Error className="text-destructive p-4 rounded-lg mb-4" />
|
|
502
|
-
* <Form.Submitted className="text-green-500 p-4 rounded-lg mb-4" />
|
|
503
|
-
* </Form.Root>
|
|
504
|
-
* );
|
|
505
|
-
* }
|
|
506
|
-
*
|
|
507
|
-
* // Pattern 2: Lazy loading with formId (Client-side)
|
|
508
|
-
* function DynamicForm({ formId }) {
|
|
509
|
-
* return (
|
|
510
|
-
* <Form.Root formServiceConfig={{ formId }}>
|
|
511
|
-
* <Form.Loading className="flex justify-center p-4" />
|
|
512
|
-
* <Form.LoadingError className="text-destructive px-4 py-3 rounded mb-4" />
|
|
513
|
-
* <Form.Fields fieldMap={FIELD_MAP} />
|
|
514
|
-
* <Form.Error className="text-destructive p-4 rounded-lg mb-4" />
|
|
515
|
-
* <Form.Submitted className="text-green-500 p-4 rounded-lg mb-4" />
|
|
516
|
-
* </Form.Root>
|
|
517
|
-
* );
|
|
518
|
-
* }
|
|
519
|
-
* ```
|
|
520
|
-
*/
|
|
521
|
-
export const Form = {
|
|
522
|
-
/** Form root component that provides service context */
|
|
523
|
-
Root,
|
|
524
|
-
/** Form loading state component */
|
|
525
|
-
Loading,
|
|
526
|
-
/** Form loading error state component */
|
|
527
|
-
LoadingError,
|
|
528
|
-
/** Form error state component */
|
|
529
|
-
Error,
|
|
530
|
-
/** Form submitted state component */
|
|
531
|
-
Submitted,
|
|
532
|
-
/** Form fields component for rendering form fields */
|
|
533
|
-
Fields,
|
|
534
|
-
};
|
|
@@ -1,4 +1,8 @@
|
|
|
1
|
+
import { forms } from '@wix/forms';
|
|
1
2
|
import { FormServiceConfig } from '../../services/form-service.js';
|
|
3
|
+
/**
|
|
4
|
+
* Props for Root headless component
|
|
5
|
+
*/
|
|
2
6
|
export interface RootProps {
|
|
3
7
|
children: React.ReactNode;
|
|
4
8
|
formServiceConfig: FormServiceConfig;
|
|
@@ -9,8 +13,9 @@ export interface RootProps {
|
|
|
9
13
|
*
|
|
10
14
|
* @order 1
|
|
11
15
|
* @component
|
|
12
|
-
* @param {
|
|
13
|
-
* @param {
|
|
16
|
+
* @param {RootProps} props - Component props
|
|
17
|
+
* @param {React.ReactNode} props.children - Child components that will have access to form context
|
|
18
|
+
* @param {FormServiceConfig} props.formServiceConfig - Configuration object containing form data
|
|
14
19
|
* @example
|
|
15
20
|
* ```tsx
|
|
16
21
|
* import { Form } from '@wix/headless-forms/react';
|
|
@@ -47,7 +52,7 @@ export interface RootProps {
|
|
|
47
52
|
* }
|
|
48
53
|
* ```
|
|
49
54
|
*/
|
|
50
|
-
export declare function Root(
|
|
55
|
+
export declare function Root({ formServiceConfig, children, }: RootProps): React.ReactNode;
|
|
51
56
|
/**
|
|
52
57
|
* Props for FormLoading headless component
|
|
53
58
|
*/
|
|
@@ -213,3 +218,44 @@ export interface FormSubmittedRenderProps {
|
|
|
213
218
|
* ```
|
|
214
219
|
*/
|
|
215
220
|
export declare function Submitted(props: FormSubmittedProps): import("react").ReactNode;
|
|
221
|
+
/**
|
|
222
|
+
* Render props for Fields component
|
|
223
|
+
*/
|
|
224
|
+
interface FieldsRenderProps {
|
|
225
|
+
form: forms.Form | null;
|
|
226
|
+
}
|
|
227
|
+
/**
|
|
228
|
+
* Props for Fields headless component
|
|
229
|
+
*/
|
|
230
|
+
interface FieldsProps {
|
|
231
|
+
children: (props: FieldsRenderProps) => React.ReactNode;
|
|
232
|
+
}
|
|
233
|
+
/**
|
|
234
|
+
* Fields component that provides form data to its children.
|
|
235
|
+
* This component accesses the form data from the service and passes it to children via render props.
|
|
236
|
+
*
|
|
237
|
+
* @component
|
|
238
|
+
* @param {FieldsProps} props - Component props
|
|
239
|
+
* @param {FieldsProps['children']} props.children - Render prop function that receives form data
|
|
240
|
+
* @example
|
|
241
|
+
* ```tsx
|
|
242
|
+
* import { Form } from '@wix/headless-forms/react';
|
|
243
|
+
*
|
|
244
|
+
* function FormFields() {
|
|
245
|
+
* return (
|
|
246
|
+
* <Form.Fields>
|
|
247
|
+
* {({ form }) => (
|
|
248
|
+
* form ? (
|
|
249
|
+
* <div>
|
|
250
|
+
* <h2>{form.name}</h2>
|
|
251
|
+
* <p>{form.description}</p>
|
|
252
|
+
* </div>
|
|
253
|
+
* ) : null
|
|
254
|
+
* )}
|
|
255
|
+
* </Form.Fields>
|
|
256
|
+
* );
|
|
257
|
+
* }
|
|
258
|
+
* ```
|
|
259
|
+
*/
|
|
260
|
+
export declare function Fields(props: FieldsProps): import("react").ReactNode;
|
|
261
|
+
export {};
|
package/dist/react/core/Form.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
2
|
import { useService, WixServices } from '@wix/services-manager-react';
|
|
3
|
-
import { FormServiceDefinition, FormService, } from '../../services/form-service.js';
|
|
4
3
|
import { createServicesMap } from '@wix/services-manager';
|
|
4
|
+
import { FormServiceDefinition, FormService, } from '../../services/form-service.js';
|
|
5
5
|
const DEFAULT_SUCCESS_MESSAGE = 'Your form has been submitted successfully.';
|
|
6
6
|
/**
|
|
7
7
|
* Root component that provides the Form service context to its children.
|
|
@@ -9,8 +9,9 @@ const DEFAULT_SUCCESS_MESSAGE = 'Your form has been submitted successfully.';
|
|
|
9
9
|
*
|
|
10
10
|
* @order 1
|
|
11
11
|
* @component
|
|
12
|
-
* @param {
|
|
13
|
-
* @param {
|
|
12
|
+
* @param {RootProps} props - Component props
|
|
13
|
+
* @param {React.ReactNode} props.children - Child components that will have access to form context
|
|
14
|
+
* @param {FormServiceConfig} props.formServiceConfig - Configuration object containing form data
|
|
14
15
|
* @example
|
|
15
16
|
* ```tsx
|
|
16
17
|
* import { Form } from '@wix/headless-forms/react';
|
|
@@ -47,8 +48,8 @@ const DEFAULT_SUCCESS_MESSAGE = 'Your form has been submitted successfully.';
|
|
|
47
48
|
* }
|
|
48
49
|
* ```
|
|
49
50
|
*/
|
|
50
|
-
export function Root(
|
|
51
|
-
return (_jsx(WixServices, { servicesMap: createServicesMap().addService(FormServiceDefinition, FormService,
|
|
51
|
+
export function Root({ formServiceConfig, children, }) {
|
|
52
|
+
return (_jsx(WixServices, { servicesMap: createServicesMap().addService(FormServiceDefinition, FormService, formServiceConfig), children: children }));
|
|
52
53
|
}
|
|
53
54
|
/**
|
|
54
55
|
* Headless component for form loading state access
|
|
@@ -74,8 +75,8 @@ export function Root(props) {
|
|
|
74
75
|
* ```
|
|
75
76
|
*/
|
|
76
77
|
export function Loading(props) {
|
|
77
|
-
const
|
|
78
|
-
const isLoading =
|
|
78
|
+
const { isLoadingSignal } = useService(FormServiceDefinition);
|
|
79
|
+
const isLoading = isLoadingSignal.get();
|
|
79
80
|
return props.children({
|
|
80
81
|
isLoading,
|
|
81
82
|
});
|
|
@@ -106,8 +107,8 @@ export function Loading(props) {
|
|
|
106
107
|
* ```
|
|
107
108
|
*/
|
|
108
109
|
export function LoadingError(props) {
|
|
109
|
-
const
|
|
110
|
-
const error =
|
|
110
|
+
const { errorSignal } = useService(FormServiceDefinition);
|
|
111
|
+
const error = errorSignal.get();
|
|
111
112
|
const hasError = !!error;
|
|
112
113
|
return props.children({
|
|
113
114
|
error,
|
|
@@ -140,10 +141,9 @@ export function LoadingError(props) {
|
|
|
140
141
|
* ```
|
|
141
142
|
*/
|
|
142
143
|
export function Error(props) {
|
|
143
|
-
|
|
144
|
-
const
|
|
145
|
-
const
|
|
146
|
-
const hasError = submitResponse.type === 'error';
|
|
144
|
+
// TODO: Implement submit response handling when submitResponseSignal is added to service
|
|
145
|
+
const error = null;
|
|
146
|
+
const hasError = false;
|
|
147
147
|
return props.children({
|
|
148
148
|
error,
|
|
149
149
|
hasError,
|
|
@@ -176,14 +176,45 @@ export function Error(props) {
|
|
|
176
176
|
* ```
|
|
177
177
|
*/
|
|
178
178
|
export function Submitted(props) {
|
|
179
|
-
|
|
180
|
-
const
|
|
181
|
-
const
|
|
182
|
-
const message = submitResponse.type === 'success'
|
|
183
|
-
? submitResponse.message || DEFAULT_SUCCESS_MESSAGE
|
|
184
|
-
: DEFAULT_SUCCESS_MESSAGE;
|
|
179
|
+
// TODO: Implement submit response handling when submitResponseSignal is added to service
|
|
180
|
+
const isSubmitted = false;
|
|
181
|
+
const message = DEFAULT_SUCCESS_MESSAGE;
|
|
185
182
|
return props.children({
|
|
186
183
|
isSubmitted,
|
|
187
184
|
message,
|
|
188
185
|
});
|
|
189
186
|
}
|
|
187
|
+
/**
|
|
188
|
+
* Fields component that provides form data to its children.
|
|
189
|
+
* This component accesses the form data from the service and passes it to children via render props.
|
|
190
|
+
*
|
|
191
|
+
* @component
|
|
192
|
+
* @param {FieldsProps} props - Component props
|
|
193
|
+
* @param {FieldsProps['children']} props.children - Render prop function that receives form data
|
|
194
|
+
* @example
|
|
195
|
+
* ```tsx
|
|
196
|
+
* import { Form } from '@wix/headless-forms/react';
|
|
197
|
+
*
|
|
198
|
+
* function FormFields() {
|
|
199
|
+
* return (
|
|
200
|
+
* <Form.Fields>
|
|
201
|
+
* {({ form }) => (
|
|
202
|
+
* form ? (
|
|
203
|
+
* <div>
|
|
204
|
+
* <h2>{form.name}</h2>
|
|
205
|
+
* <p>{form.description}</p>
|
|
206
|
+
* </div>
|
|
207
|
+
* ) : null
|
|
208
|
+
* )}
|
|
209
|
+
* </Form.Fields>
|
|
210
|
+
* );
|
|
211
|
+
* }
|
|
212
|
+
* ```
|
|
213
|
+
*/
|
|
214
|
+
export function Fields(props) {
|
|
215
|
+
const { formSignal } = useService(FormServiceDefinition);
|
|
216
|
+
const form = formSignal.get();
|
|
217
|
+
return props.children({
|
|
218
|
+
form,
|
|
219
|
+
});
|
|
220
|
+
}
|
|
@@ -1,5 +1,9 @@
|
|
|
1
1
|
import { forms } from '@wix/forms';
|
|
2
|
-
import { type
|
|
2
|
+
import { type ReadOnlySignal } from '@wix/services-definitions/core-services/signals';
|
|
3
|
+
/**
|
|
4
|
+
* Response type for form submission operations.
|
|
5
|
+
* Represents the different states a form submission can be in.
|
|
6
|
+
*/
|
|
3
7
|
export type SubmitResponse = {
|
|
4
8
|
type: 'success';
|
|
5
9
|
message?: string;
|
|
@@ -9,181 +13,78 @@ export type SubmitResponse = {
|
|
|
9
13
|
} | {
|
|
10
14
|
type: 'idle';
|
|
11
15
|
};
|
|
16
|
+
/**
|
|
17
|
+
* API interface for the Form service, providing reactive form data management.
|
|
18
|
+
* This service handles loading and managing form data, loading state, and errors.
|
|
19
|
+
* It supports both pre-loaded form data and lazy loading with form IDs.
|
|
20
|
+
*
|
|
21
|
+
* @interface FormServiceAPI
|
|
22
|
+
*/
|
|
12
23
|
export interface FormServiceAPI {
|
|
13
|
-
form
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
24
|
+
/** Reactive signal containing the current form data */
|
|
25
|
+
formSignal: ReadOnlySignal<forms.Form | null>;
|
|
26
|
+
/** Reactive signal indicating if a form is currently being loaded */
|
|
27
|
+
isLoadingSignal: ReadOnlySignal<boolean>;
|
|
28
|
+
/** Reactive signal containing any error message, or null if no error */
|
|
29
|
+
errorSignal: ReadOnlySignal<string | null>;
|
|
17
30
|
}
|
|
31
|
+
/**
|
|
32
|
+
* Service definition for the Form service.
|
|
33
|
+
* This defines the contract that the FormService must implement.
|
|
34
|
+
*
|
|
35
|
+
* @constant
|
|
36
|
+
*/
|
|
18
37
|
export declare const FormServiceDefinition: string & {
|
|
19
38
|
__api: FormServiceAPI;
|
|
20
39
|
__config: {};
|
|
21
40
|
isServiceDefinition?: boolean;
|
|
22
41
|
} & FormServiceAPI;
|
|
23
42
|
/**
|
|
24
|
-
* Configuration
|
|
25
|
-
*
|
|
26
|
-
*
|
|
27
|
-
*
|
|
28
|
-
* **Pattern 1: Pre-loaded Form Data (SSR/SSG)**
|
|
29
|
-
* - Use when you have form data available at service initialization
|
|
30
|
-
* - Recommended for server-side rendering and static site generation
|
|
31
|
-
* - Provides immediate form availability with no loading states
|
|
32
|
-
* - Better performance and SEO as form data is available immediately
|
|
43
|
+
* Configuration type for the Form service.
|
|
44
|
+
* Supports two distinct patterns for providing form data:
|
|
45
|
+
* - Pre-loaded form data (SSR/SSG scenarios)
|
|
46
|
+
* - Lazy loading with form ID (client-side routing)
|
|
33
47
|
*
|
|
34
|
-
*
|
|
35
|
-
* - Use when you only have a form ID and need to load form data asynchronously
|
|
36
|
-
* - Ideal for client-side routing and dynamic form loading
|
|
37
|
-
* - Service will automatically fetch form data using the provided formId
|
|
38
|
-
* - Provides loading states and error handling during form fetch
|
|
39
|
-
*
|
|
40
|
-
* @interface FormServiceConfig
|
|
41
|
-
* @property {forms.Form} [form] - Pre-loaded form data. When provided, the service uses this data immediately without any network requests. Recommended for SSR/SSG scenarios.
|
|
42
|
-
* @property {string} [formId] - Form ID for lazy loading. When provided (and no form data), the service will fetch form data asynchronously from the Wix Forms API. Ideal for client-side routing.
|
|
43
|
-
*
|
|
44
|
-
* @example
|
|
45
|
-
* ```tsx
|
|
46
|
-
* // Pattern 1: Pre-loaded form data (SSR/SSG)
|
|
47
|
-
* // Server-side: Load form data first
|
|
48
|
-
* const formServiceConfigResult = await loadFormServiceConfig('form-123');
|
|
49
|
-
* if (formServiceConfigResult.type === 'success') {
|
|
50
|
-
* // Use pre-loaded form data
|
|
51
|
-
* <Form.Root formServiceConfig={formServiceConfigResult.config} />
|
|
52
|
-
* }
|
|
53
|
-
*
|
|
54
|
-
* // Or with direct form data
|
|
55
|
-
* const config1: FormServiceConfig = { form: myForm };
|
|
56
|
-
* <Form.Root formServiceConfig={config1} />
|
|
57
|
-
* ```
|
|
58
|
-
*
|
|
59
|
-
* @example
|
|
60
|
-
* ```tsx
|
|
61
|
-
* // Pattern 2: Lazy loading with form ID (Client-side)
|
|
62
|
-
* // Simple formId-based loading - service handles the rest
|
|
63
|
-
* const config2: FormServiceConfig = { formId: 'form-123' };
|
|
64
|
-
* <Form.Root formServiceConfig={config2} />
|
|
65
|
-
*
|
|
66
|
-
* // With loading and error handling
|
|
67
|
-
* <Form.Root formServiceConfig={{ formId: 'form-123' }}>
|
|
68
|
-
* <Form.Loading>
|
|
69
|
-
* {({ isLoading }) => isLoading ? <div>Loading form...</div> : null}
|
|
70
|
-
* </Form.Loading>
|
|
71
|
-
* <Form.LoadingError>
|
|
72
|
-
* {({ error, hasError }) => hasError ? <div>Error: {error}</div> : null}
|
|
73
|
-
* </Form.LoadingError>
|
|
74
|
-
* <Form.Fields fieldMap={FIELD_MAP} />
|
|
75
|
-
* </Form.Root>
|
|
76
|
-
* ```
|
|
77
|
-
*
|
|
78
|
-
* @example
|
|
79
|
-
* ```tsx
|
|
80
|
-
* // Pattern 3: Both provided (form takes precedence)
|
|
81
|
-
* // The pre-loaded form data will be used, formId is ignored
|
|
82
|
-
* const config3: FormServiceConfig = {
|
|
83
|
-
* form: myForm,
|
|
84
|
-
* formId: 'form-123' // This will be ignored
|
|
85
|
-
* };
|
|
86
|
-
* <Form.Root formServiceConfig={config3} />
|
|
87
|
-
* ```
|
|
88
|
-
*
|
|
89
|
-
* @throws {Error} Throws an error if neither form nor formId is provided
|
|
48
|
+
* @type {FormServiceConfig}
|
|
90
49
|
*/
|
|
91
|
-
export
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
50
|
+
export type FormServiceConfig = {
|
|
51
|
+
formId: string;
|
|
52
|
+
} | {
|
|
53
|
+
form: forms.Form;
|
|
54
|
+
};
|
|
95
55
|
/**
|
|
96
|
-
* Form service
|
|
97
|
-
*
|
|
98
|
-
*
|
|
99
|
-
* It automatically handles form loading when only a formId is provided, making it suitable for both SSR and client-side scenarios.
|
|
100
|
-
*
|
|
101
|
-
* ## Service Behavior
|
|
102
|
-
*
|
|
103
|
-
* **Configuration Resolution:**
|
|
104
|
-
* - If `form` is provided: Uses pre-loaded form data immediately (SSR/SSG pattern)
|
|
105
|
-
* - If only `formId` is provided: Loads form data asynchronously from Wix Forms API
|
|
106
|
-
* - If both are provided: Uses pre-loaded `form` data and ignores `formId`
|
|
107
|
-
* - If neither is provided: Throws an error during service initialization
|
|
108
|
-
*
|
|
109
|
-
* **Loading States:**
|
|
110
|
-
* - `isLoading`: `true` when loading form data via `formId`, `false` otherwise
|
|
111
|
-
* - `form`: `null` initially when using `formId`, populated after successful load
|
|
112
|
-
* - `error`: `null` initially, populated if form loading fails
|
|
113
|
-
* - `submitResponse`: `{ type: 'idle' }` initially, updated during form submission
|
|
114
|
-
*
|
|
115
|
-
* **Error Handling:**
|
|
116
|
-
* - Network errors during form loading are caught and stored in the `error` signal
|
|
117
|
-
* - "Form not found" errors are handled when the formId doesn't exist
|
|
118
|
-
* - All errors are logged to console for debugging
|
|
56
|
+
* Implementation of the Form service that manages reactive form data.
|
|
57
|
+
* This service provides signals for form data, loading state, and error handling.
|
|
58
|
+
* It supports both pre-loaded form data and lazy loading with form IDs.
|
|
119
59
|
*
|
|
120
60
|
* @example
|
|
121
61
|
* ```tsx
|
|
122
|
-
* //
|
|
123
|
-
* const
|
|
62
|
+
* // Pre-loaded form data (SSR/SSG)
|
|
63
|
+
* const formService = FormService.withConfig({ form: formData });
|
|
124
64
|
*
|
|
125
|
-
* //
|
|
126
|
-
* const
|
|
127
|
-
*
|
|
128
|
-
* // Access form data (null during loading)
|
|
129
|
-
* const form = service.form.get();
|
|
130
|
-
*
|
|
131
|
-
* // Check for errors
|
|
132
|
-
* const error = service.error.get();
|
|
65
|
+
* // Lazy loading with form ID (client-side)
|
|
66
|
+
* const formService = FormService.withConfig({ formId: 'form-123' });
|
|
133
67
|
* ```
|
|
134
|
-
*
|
|
135
68
|
*/
|
|
136
69
|
export declare const FormService: import("@wix/services-definitions").ServiceFactory<string & {
|
|
137
70
|
__api: FormServiceAPI;
|
|
138
71
|
__config: {};
|
|
139
72
|
isServiceDefinition?: boolean;
|
|
140
73
|
} & FormServiceAPI, FormServiceConfig>;
|
|
141
|
-
export type FormServiceConfigResult = {
|
|
142
|
-
type: 'success';
|
|
143
|
-
config: FormServiceConfig;
|
|
144
|
-
} | {
|
|
145
|
-
type: 'notFound';
|
|
146
|
-
};
|
|
147
74
|
/**
|
|
148
|
-
* Loads form service configuration
|
|
149
|
-
*
|
|
150
|
-
*
|
|
151
|
-
* object that can be used to initialize the Form service. This is the recommended approach
|
|
152
|
-
* for server-side rendering (SSR) and static site generation (SSG) scenarios.
|
|
153
|
-
*
|
|
154
|
-
* @param {string} id - The unique identifier of the form to load
|
|
155
|
-
* @returns {Promise<FormServiceConfigResult>} A promise that resolves to either:
|
|
156
|
-
* - `{ type: 'success', config: FormServiceConfig }` if the form is found and loaded successfully
|
|
157
|
-
* - `{ type: 'notFound' }` if the form doesn't exist or an error occurs during loading
|
|
158
|
-
*
|
|
159
|
-
* @example
|
|
160
|
-
* ```tsx
|
|
161
|
-
* import { loadFormServiceConfig } from '@wix/headless-forms/services';
|
|
162
|
-
*
|
|
163
|
-
* // Server-side loading (Astro/SSR) - pre-loads form data
|
|
164
|
-
* const formServiceConfigResult = await loadFormServiceConfig('form-id');
|
|
75
|
+
* Loads form service configuration from the Wix Forms API for SSR initialization.
|
|
76
|
+
* This function is designed to be used during Server-Side Rendering (SSR) to preload
|
|
77
|
+
* a specific form by ID that will be used to configure the FormService.
|
|
165
78
|
*
|
|
166
|
-
*
|
|
167
|
-
*
|
|
168
|
-
* }
|
|
169
|
-
*
|
|
170
|
-
* // Use pre-loaded form data
|
|
171
|
-
* const formServiceConfig = formServiceConfigResult.config;
|
|
172
|
-
* <Form.Root formServiceConfig={formServiceConfig} />
|
|
173
|
-
* ```
|
|
79
|
+
* @param {string} formId - The unique identifier of the form to load
|
|
80
|
+
* @returns {Promise<FormServiceConfig>} Configuration object with pre-loaded form data
|
|
81
|
+
* @throws {Error} When the form cannot be loaded
|
|
174
82
|
*
|
|
175
83
|
* @example
|
|
176
84
|
* ```tsx
|
|
177
|
-
* //
|
|
178
|
-
*
|
|
179
|
-
*
|
|
180
|
-
* <Form.Loading>
|
|
181
|
-
* {({ isLoading }) => isLoading ? <div>Loading...</div> : null}
|
|
182
|
-
* </Form.Loading>
|
|
183
|
-
* <Form.Fields fieldMap={FIELD_MAP} />
|
|
184
|
-
* </Form.Root>
|
|
85
|
+
* // In your SSR/SSG setup
|
|
86
|
+
* const formConfig = await loadFormServiceConfig('form-123');
|
|
87
|
+
* const formService = FormService.withConfig(formConfig);
|
|
185
88
|
* ```
|
|
186
|
-
*
|
|
187
|
-
* @throws {Error} Logs errors to console but returns 'notFound' result instead of throwing
|
|
188
89
|
*/
|
|
189
|
-
export declare function loadFormServiceConfig(
|
|
90
|
+
export declare function loadFormServiceConfig(formId: string): Promise<FormServiceConfig>;
|