@wix/headless-forms 0.0.8 → 0.0.9
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/cjs/dist/react/Form.d.ts +1 -1
- package/cjs/dist/react/Form.js +2 -3
- package/cjs/dist/react/core/Form.d.ts +10 -4
- package/cjs/dist/react/core/Form.js +20 -11
- package/cjs/dist/react/types.d.ts +3 -1251
- package/cjs/dist/services/form-service.d.ts +25 -3
- package/cjs/dist/services/form-service.js +55 -2
- package/dist/react/Form.d.ts +1 -1
- package/dist/react/Form.js +2 -3
- package/dist/react/core/Form.d.ts +10 -4
- package/dist/react/core/Form.js +20 -11
- package/dist/react/types.d.ts +3 -1251
- package/dist/services/form-service.d.ts +25 -3
- package/dist/services/form-service.js +56 -3
- package/package.json +3 -3
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { forms } from '@wix/forms';
|
|
2
2
|
import { type ReadOnlySignal } from '@wix/services-definitions/core-services/signals';
|
|
3
|
+
import { FormValues } from '../react/types.js';
|
|
3
4
|
/**
|
|
4
5
|
* Response type for form submission operations.
|
|
5
6
|
* Represents the different states a form submission can be in.
|
|
@@ -15,7 +16,7 @@ export type SubmitResponse = {
|
|
|
15
16
|
};
|
|
16
17
|
/**
|
|
17
18
|
* API interface for the Form service, providing reactive form data management.
|
|
18
|
-
* This service handles loading and managing form data, loading state, and
|
|
19
|
+
* This service handles loading and managing form data, loading state, errors, and submissions.
|
|
19
20
|
* It supports both pre-loaded form data and lazy loading with form IDs.
|
|
20
21
|
*
|
|
21
22
|
* @interface FormServiceAPI
|
|
@@ -27,6 +28,10 @@ export interface FormServiceAPI {
|
|
|
27
28
|
isLoadingSignal: ReadOnlySignal<boolean>;
|
|
28
29
|
/** Reactive signal containing any error message, or null if no error */
|
|
29
30
|
errorSignal: ReadOnlySignal<string | null>;
|
|
31
|
+
/** Reactive signal containing submission response state */
|
|
32
|
+
submitResponseSignal: ReadOnlySignal<SubmitResponse>;
|
|
33
|
+
/** Function to submit form with current values */
|
|
34
|
+
submitForm: (formValues: FormValues) => Promise<void>;
|
|
30
35
|
}
|
|
31
36
|
/**
|
|
32
37
|
* Service definition for the Form service.
|
|
@@ -39,23 +44,29 @@ export declare const FormServiceDefinition: string & {
|
|
|
39
44
|
__config: {};
|
|
40
45
|
isServiceDefinition?: boolean;
|
|
41
46
|
} & FormServiceAPI;
|
|
47
|
+
type OnSubmit = (formId: string, formValues: FormValues) => Promise<SubmitResponse>;
|
|
42
48
|
/**
|
|
43
49
|
* Configuration type for the Form service.
|
|
44
50
|
* Supports two distinct patterns for providing form data:
|
|
45
51
|
* - Pre-loaded form data (SSR/SSG scenarios)
|
|
46
52
|
* - Lazy loading with form ID (client-side routing)
|
|
47
53
|
*
|
|
54
|
+
* Optionally accepts a custom submission handler to override default behavior.
|
|
55
|
+
*
|
|
48
56
|
* @type {FormServiceConfig}
|
|
49
57
|
*/
|
|
50
58
|
export type FormServiceConfig = {
|
|
51
59
|
formId: string;
|
|
60
|
+
onSubmit?: OnSubmit;
|
|
52
61
|
} | {
|
|
53
62
|
form: forms.Form;
|
|
63
|
+
onSubmit?: OnSubmit;
|
|
54
64
|
};
|
|
55
65
|
/**
|
|
56
|
-
* Implementation of the Form service that manages reactive form data.
|
|
57
|
-
* This service provides signals for form data, loading state, and
|
|
66
|
+
* Implementation of the Form service that manages reactive form data and submissions.
|
|
67
|
+
* This service provides signals for form data, loading state, error handling, and submission state.
|
|
58
68
|
* It supports both pre-loaded form data and lazy loading with form IDs.
|
|
69
|
+
* Consumers can provide a custom submission handler via config.
|
|
59
70
|
*
|
|
60
71
|
* @example
|
|
61
72
|
* ```tsx
|
|
@@ -64,6 +75,16 @@ export type FormServiceConfig = {
|
|
|
64
75
|
*
|
|
65
76
|
* // Lazy loading with form ID (client-side)
|
|
66
77
|
* const formService = FormService.withConfig({ formId: 'form-123' });
|
|
78
|
+
*
|
|
79
|
+
* // With custom submission handler
|
|
80
|
+
* const formService = FormService.withConfig({
|
|
81
|
+
* formId: 'form-123',
|
|
82
|
+
* onSubmit: async (formId, formValues) => {
|
|
83
|
+
* // Custom submission logic
|
|
84
|
+
* await fetch('/api/submit', { method: 'POST', body: JSON.stringify({ formId, ...formValues }) });
|
|
85
|
+
* return { type: 'success', message: 'Form submitted!' };
|
|
86
|
+
* }
|
|
87
|
+
* });
|
|
67
88
|
* ```
|
|
68
89
|
*/
|
|
69
90
|
export declare const FormService: import("@wix/services-definitions").ServiceFactory<string & {
|
|
@@ -88,3 +109,4 @@ export declare const FormService: import("@wix/services-definitions").ServiceFac
|
|
|
88
109
|
* ```
|
|
89
110
|
*/
|
|
90
111
|
export declare function loadFormServiceConfig(formId: string): Promise<FormServiceConfig>;
|
|
112
|
+
export {};
|
|
@@ -13,9 +13,10 @@ const signals_1 = require("@wix/services-definitions/core-services/signals");
|
|
|
13
13
|
*/
|
|
14
14
|
exports.FormServiceDefinition = (0, services_definitions_1.defineService)('formService');
|
|
15
15
|
/**
|
|
16
|
-
* Implementation of the Form service that manages reactive form data.
|
|
17
|
-
* This service provides signals for form data, loading state, and
|
|
16
|
+
* Implementation of the Form service that manages reactive form data and submissions.
|
|
17
|
+
* This service provides signals for form data, loading state, error handling, and submission state.
|
|
18
18
|
* It supports both pre-loaded form data and lazy loading with form IDs.
|
|
19
|
+
* Consumers can provide a custom submission handler via config.
|
|
19
20
|
*
|
|
20
21
|
* @example
|
|
21
22
|
* ```tsx
|
|
@@ -24,12 +25,25 @@ exports.FormServiceDefinition = (0, services_definitions_1.defineService)('formS
|
|
|
24
25
|
*
|
|
25
26
|
* // Lazy loading with form ID (client-side)
|
|
26
27
|
* const formService = FormService.withConfig({ formId: 'form-123' });
|
|
28
|
+
*
|
|
29
|
+
* // With custom submission handler
|
|
30
|
+
* const formService = FormService.withConfig({
|
|
31
|
+
* formId: 'form-123',
|
|
32
|
+
* onSubmit: async (formId, formValues) => {
|
|
33
|
+
* // Custom submission logic
|
|
34
|
+
* await fetch('/api/submit', { method: 'POST', body: JSON.stringify({ formId, ...formValues }) });
|
|
35
|
+
* return { type: 'success', message: 'Form submitted!' };
|
|
36
|
+
* }
|
|
37
|
+
* });
|
|
27
38
|
* ```
|
|
28
39
|
*/
|
|
29
40
|
exports.FormService = services_definitions_1.implementService.withConfig()(exports.FormServiceDefinition, ({ getService, config }) => {
|
|
30
41
|
const signalsService = getService(signals_1.SignalsServiceDefinition);
|
|
31
42
|
const isLoadingSignal = signalsService.signal(false);
|
|
32
43
|
const errorSignal = signalsService.signal(null);
|
|
44
|
+
const submitResponseSignal = signalsService.signal({
|
|
45
|
+
type: 'idle',
|
|
46
|
+
});
|
|
33
47
|
const hasSchema = 'form' in config;
|
|
34
48
|
const formSignal = signalsService.signal(hasSchema ? config.form : null);
|
|
35
49
|
if (!hasSchema) {
|
|
@@ -55,10 +69,49 @@ exports.FormService = services_definitions_1.implementService.withConfig()(expor
|
|
|
55
69
|
isLoadingSignal.set(false);
|
|
56
70
|
}
|
|
57
71
|
}
|
|
72
|
+
async function defaultSubmitHandler(formId, formValues) {
|
|
73
|
+
try {
|
|
74
|
+
await forms_1.submissions.createSubmission({ formId, ...formValues });
|
|
75
|
+
// TODO: add message
|
|
76
|
+
return { type: 'success' };
|
|
77
|
+
}
|
|
78
|
+
catch (error) {
|
|
79
|
+
console.error('Form submission failed:', error);
|
|
80
|
+
return { type: 'error', message: 'Failed to submit form' };
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
/**
|
|
84
|
+
* Submits the form with the provided values.
|
|
85
|
+
* Uses custom handler if provided in config, otherwise uses default submission.
|
|
86
|
+
*/
|
|
87
|
+
async function submitForm(formValues) {
|
|
88
|
+
const form = formSignal.get();
|
|
89
|
+
if (!form) {
|
|
90
|
+
console.error('Cannot submit: form not loaded');
|
|
91
|
+
return;
|
|
92
|
+
}
|
|
93
|
+
// @ts-expect-error
|
|
94
|
+
const formId = form._id ? form._id : form.id;
|
|
95
|
+
submitResponseSignal.set({ type: 'idle' });
|
|
96
|
+
try {
|
|
97
|
+
const handler = config.onSubmit || defaultSubmitHandler;
|
|
98
|
+
const response = await handler(formId, formValues);
|
|
99
|
+
submitResponseSignal.set(response);
|
|
100
|
+
}
|
|
101
|
+
catch (error) {
|
|
102
|
+
console.error('Unexpected error during submission:', error);
|
|
103
|
+
submitResponseSignal.set({
|
|
104
|
+
type: 'error',
|
|
105
|
+
message: 'Unexpected error during submission',
|
|
106
|
+
});
|
|
107
|
+
}
|
|
108
|
+
}
|
|
58
109
|
return {
|
|
59
110
|
formSignal: formSignal,
|
|
60
111
|
isLoadingSignal: isLoadingSignal,
|
|
61
112
|
errorSignal: errorSignal,
|
|
113
|
+
submitResponseSignal: submitResponseSignal,
|
|
114
|
+
submitForm: submitForm,
|
|
62
115
|
};
|
|
63
116
|
});
|
|
64
117
|
async function fetchForm(id) {
|
package/dist/react/Form.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
|
+
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';
|
|
2
3
|
import { type FormServiceConfig } from '../services/form-service';
|
|
3
|
-
import { 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 } from './types.js';
|
|
4
4
|
/**
|
|
5
5
|
* Props for the Form root component following the documented API
|
|
6
6
|
*/
|
package/dist/react/Form.js
CHANGED
|
@@ -457,10 +457,9 @@ export const Fields = React.forwardRef((props, ref) => {
|
|
|
457
457
|
const handleFormValidate = useCallback((errors) => {
|
|
458
458
|
setFormErrors(errors);
|
|
459
459
|
}, []);
|
|
460
|
-
return (_jsx(CoreFields, { children: ({ form }) => {
|
|
461
|
-
console.log('Fields form', form);
|
|
460
|
+
return (_jsx(CoreFields, { children: ({ form, submitForm }) => {
|
|
462
461
|
if (!form)
|
|
463
462
|
return null;
|
|
464
|
-
return (_jsx("div", { ref: ref, children: _jsx(FormViewer, { form: form, values: formValues, onChange: handleFormChange, errors: formErrors, onValidate: handleFormValidate, fields: props.fieldMap }) }));
|
|
463
|
+
return (_jsx("div", { ref: ref, children: _jsx(FormViewer, { form: form, values: formValues, onChange: handleFormChange, errors: formErrors, onValidate: handleFormValidate, fields: props.fieldMap, submitForm: () => submitForm(formValues) }) }));
|
|
465
464
|
} }));
|
|
466
465
|
});
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { forms } from '@wix/forms';
|
|
2
2
|
import { FormServiceConfig } from '../../services/form-service.js';
|
|
3
|
+
import { FormValues } from '../types.js';
|
|
3
4
|
/**
|
|
4
5
|
* Props for Root headless component
|
|
5
6
|
*/
|
|
@@ -223,6 +224,7 @@ export declare function Submitted(props: FormSubmittedProps): import("react").Re
|
|
|
223
224
|
*/
|
|
224
225
|
interface FieldsRenderProps {
|
|
225
226
|
form: forms.Form | null;
|
|
227
|
+
submitForm: (formValues: FormValues) => Promise<void>;
|
|
226
228
|
}
|
|
227
229
|
/**
|
|
228
230
|
* Props for Fields headless component
|
|
@@ -231,12 +233,13 @@ interface FieldsProps {
|
|
|
231
233
|
children: (props: FieldsRenderProps) => React.ReactNode;
|
|
232
234
|
}
|
|
233
235
|
/**
|
|
234
|
-
* Fields component that provides form data to its children.
|
|
235
|
-
* This component accesses the form data
|
|
236
|
+
* Fields component that provides form data and actions to its children.
|
|
237
|
+
* This component accesses the form data and submitForm action from the service
|
|
238
|
+
* and passes them to children via render props.
|
|
236
239
|
*
|
|
237
240
|
* @component
|
|
238
241
|
* @param {FieldsProps} props - Component props
|
|
239
|
-
* @param {FieldsProps['children']} props.children - Render prop function that receives form data
|
|
242
|
+
* @param {FieldsProps['children']} props.children - Render prop function that receives form data and actions
|
|
240
243
|
* @example
|
|
241
244
|
* ```tsx
|
|
242
245
|
* import { Form } from '@wix/headless-forms/react';
|
|
@@ -244,11 +247,14 @@ interface FieldsProps {
|
|
|
244
247
|
* function FormFields() {
|
|
245
248
|
* return (
|
|
246
249
|
* <Form.Fields>
|
|
247
|
-
* {({ form }) => (
|
|
250
|
+
* {({ form, submitForm }) => (
|
|
248
251
|
* form ? (
|
|
249
252
|
* <div>
|
|
250
253
|
* <h2>{form.name}</h2>
|
|
251
254
|
* <p>{form.description}</p>
|
|
255
|
+
* <button onClick={() => submitForm({ field1: 'value' })}>
|
|
256
|
+
* Submit
|
|
257
|
+
* </button>
|
|
252
258
|
* </div>
|
|
253
259
|
* ) : null
|
|
254
260
|
* )}
|
package/dist/react/core/Form.js
CHANGED
|
@@ -141,9 +141,10 @@ export function LoadingError(props) {
|
|
|
141
141
|
* ```
|
|
142
142
|
*/
|
|
143
143
|
export function Error(props) {
|
|
144
|
-
|
|
145
|
-
const
|
|
146
|
-
const
|
|
144
|
+
const { submitResponseSignal } = useService(FormServiceDefinition);
|
|
145
|
+
const submitResponse = submitResponseSignal.get();
|
|
146
|
+
const error = submitResponse.type === 'error' ? submitResponse.message : null;
|
|
147
|
+
const hasError = submitResponse.type === 'error';
|
|
147
148
|
return props.children({
|
|
148
149
|
error,
|
|
149
150
|
hasError,
|
|
@@ -176,21 +177,25 @@ export function Error(props) {
|
|
|
176
177
|
* ```
|
|
177
178
|
*/
|
|
178
179
|
export function Submitted(props) {
|
|
179
|
-
|
|
180
|
-
const
|
|
181
|
-
const
|
|
180
|
+
const { submitResponseSignal } = useService(FormServiceDefinition);
|
|
181
|
+
const submitResponse = submitResponseSignal.get();
|
|
182
|
+
const isSubmitted = submitResponse.type === 'success';
|
|
183
|
+
const message = submitResponse.type === 'success'
|
|
184
|
+
? submitResponse.message || DEFAULT_SUCCESS_MESSAGE
|
|
185
|
+
: DEFAULT_SUCCESS_MESSAGE;
|
|
182
186
|
return props.children({
|
|
183
187
|
isSubmitted,
|
|
184
188
|
message,
|
|
185
189
|
});
|
|
186
190
|
}
|
|
187
191
|
/**
|
|
188
|
-
* Fields component that provides form data to its children.
|
|
189
|
-
* This component accesses the form data
|
|
192
|
+
* Fields component that provides form data and actions to its children.
|
|
193
|
+
* This component accesses the form data and submitForm action from the service
|
|
194
|
+
* and passes them to children via render props.
|
|
190
195
|
*
|
|
191
196
|
* @component
|
|
192
197
|
* @param {FieldsProps} props - Component props
|
|
193
|
-
* @param {FieldsProps['children']} props.children - Render prop function that receives form data
|
|
198
|
+
* @param {FieldsProps['children']} props.children - Render prop function that receives form data and actions
|
|
194
199
|
* @example
|
|
195
200
|
* ```tsx
|
|
196
201
|
* import { Form } from '@wix/headless-forms/react';
|
|
@@ -198,11 +203,14 @@ export function Submitted(props) {
|
|
|
198
203
|
* function FormFields() {
|
|
199
204
|
* return (
|
|
200
205
|
* <Form.Fields>
|
|
201
|
-
* {({ form }) => (
|
|
206
|
+
* {({ form, submitForm }) => (
|
|
202
207
|
* form ? (
|
|
203
208
|
* <div>
|
|
204
209
|
* <h2>{form.name}</h2>
|
|
205
210
|
* <p>{form.description}</p>
|
|
211
|
+
* <button onClick={() => submitForm({ field1: 'value' })}>
|
|
212
|
+
* Submit
|
|
213
|
+
* </button>
|
|
206
214
|
* </div>
|
|
207
215
|
* ) : null
|
|
208
216
|
* )}
|
|
@@ -212,9 +220,10 @@ export function Submitted(props) {
|
|
|
212
220
|
* ```
|
|
213
221
|
*/
|
|
214
222
|
export function Fields(props) {
|
|
215
|
-
const { formSignal } = useService(FormServiceDefinition);
|
|
223
|
+
const { formSignal, submitForm } = useService(FormServiceDefinition);
|
|
216
224
|
const form = formSignal.get();
|
|
217
225
|
return props.children({
|
|
218
226
|
form,
|
|
227
|
+
submitForm,
|
|
219
228
|
});
|
|
220
229
|
}
|