@wix/headless-forms 0.0.0
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 +802 -0
- package/cjs/dist/react/Form.js +776 -0
- package/cjs/dist/react/Phone.d.ts +47 -0
- package/cjs/dist/react/Phone.js +56 -0
- package/cjs/dist/react/constants/calling-country-codes.d.ts +242 -0
- package/cjs/dist/react/constants/calling-country-codes.js +242 -0
- package/cjs/dist/react/context/FieldContext.d.ts +12 -0
- package/cjs/dist/react/context/FieldContext.js +16 -0
- package/cjs/dist/react/context/FieldLayoutContext.d.ts +12 -0
- package/cjs/dist/react/context/FieldLayoutContext.js +21 -0
- package/cjs/dist/react/core/Form.d.ts +342 -0
- package/cjs/dist/react/core/Form.js +278 -0
- package/cjs/dist/react/index.d.ts +3 -0
- package/cjs/dist/react/index.js +42 -0
- package/cjs/dist/react/types.d.ts +3 -0
- package/cjs/dist/react/types.js +2 -0
- package/cjs/dist/react/utils.d.ts +13 -0
- package/cjs/dist/react/utils.js +20 -0
- package/cjs/dist/services/form-service.d.ts +114 -0
- package/cjs/dist/services/form-service.js +152 -0
- package/cjs/dist/services/index.d.ts +1 -0
- package/cjs/dist/services/index.js +17 -0
- package/cjs/package.json +3 -0
- package/dist/react/Form.d.ts +802 -0
- package/dist/react/Form.js +740 -0
- package/dist/react/Phone.d.ts +47 -0
- package/dist/react/Phone.js +50 -0
- package/dist/react/constants/calling-country-codes.d.ts +242 -0
- package/dist/react/constants/calling-country-codes.js +241 -0
- package/dist/react/context/FieldContext.d.ts +12 -0
- package/dist/react/context/FieldContext.js +9 -0
- package/dist/react/context/FieldLayoutContext.d.ts +12 -0
- package/dist/react/context/FieldLayoutContext.js +13 -0
- package/dist/react/core/Form.d.ts +342 -0
- package/dist/react/core/Form.js +269 -0
- package/dist/react/index.d.ts +3 -0
- package/dist/react/index.js +3 -0
- package/dist/react/types.d.ts +3 -0
- package/dist/react/types.js +1 -0
- package/dist/react/utils.d.ts +13 -0
- package/dist/react/utils.js +17 -0
- package/dist/services/form-service.d.ts +114 -0
- package/dist/services/form-service.js +148 -0
- package/dist/services/index.d.ts +1 -0
- package/dist/services/index.js +1 -0
- package/package.json +62 -0
- package/react/package.json +4 -0
- package/services/package.json +4 -0
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
import { forms } from '@wix/forms';
|
|
2
|
+
import { type ReadOnlySignal } from '@wix/services-definitions/core-services/signals';
|
|
3
|
+
import { FormValues } from '../react/types.js';
|
|
4
|
+
/**
|
|
5
|
+
* Response type for form submission operations.
|
|
6
|
+
* Represents the different states a form submission can be in.
|
|
7
|
+
*/
|
|
8
|
+
export type SubmitResponse = {
|
|
9
|
+
type: 'success';
|
|
10
|
+
message?: string;
|
|
11
|
+
} | {
|
|
12
|
+
type: 'error';
|
|
13
|
+
message: string;
|
|
14
|
+
} | {
|
|
15
|
+
type: 'idle';
|
|
16
|
+
} | {
|
|
17
|
+
type: 'loading';
|
|
18
|
+
};
|
|
19
|
+
/**
|
|
20
|
+
* API interface for the Form service, providing reactive form data management.
|
|
21
|
+
* This service handles loading and managing form data, loading state, errors, and submissions.
|
|
22
|
+
* It supports both pre-loaded form data and lazy loading with form IDs.
|
|
23
|
+
*
|
|
24
|
+
* @interface FormServiceAPI
|
|
25
|
+
*/
|
|
26
|
+
export interface FormServiceAPI {
|
|
27
|
+
/** Reactive signal containing the current form data */
|
|
28
|
+
formSignal: ReadOnlySignal<forms.Form | null>;
|
|
29
|
+
/** Reactive signal indicating if a form is currently being loaded */
|
|
30
|
+
isLoadingSignal: ReadOnlySignal<boolean>;
|
|
31
|
+
/** Reactive signal containing any error message, or null if no error */
|
|
32
|
+
errorSignal: ReadOnlySignal<string | null>;
|
|
33
|
+
/** Reactive signal containing submission response state */
|
|
34
|
+
submitResponseSignal: ReadOnlySignal<SubmitResponse>;
|
|
35
|
+
/** Function to submit form with current values */
|
|
36
|
+
submitForm: (formValues: FormValues) => Promise<void>;
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Service definition for the Form service.
|
|
40
|
+
* This defines the contract that the FormService must implement.
|
|
41
|
+
*
|
|
42
|
+
* @constant
|
|
43
|
+
*/
|
|
44
|
+
export declare const FormServiceDefinition: string & {
|
|
45
|
+
__api: FormServiceAPI;
|
|
46
|
+
__config: {};
|
|
47
|
+
isServiceDefinition?: boolean;
|
|
48
|
+
} & FormServiceAPI;
|
|
49
|
+
type OnSubmit = (formId: string, formValues: FormValues) => Promise<SubmitResponse>;
|
|
50
|
+
/**
|
|
51
|
+
* Configuration type for the Form service.
|
|
52
|
+
* Supports two distinct patterns for providing form data:
|
|
53
|
+
* - Pre-loaded form data (SSR/SSG scenarios)
|
|
54
|
+
* - Lazy loading with form ID (client-side routing)
|
|
55
|
+
*
|
|
56
|
+
* Optionally accepts a custom submission handler to override default behavior.
|
|
57
|
+
*
|
|
58
|
+
* @type {FormServiceConfig}
|
|
59
|
+
*/
|
|
60
|
+
export type FormServiceConfig = {
|
|
61
|
+
formId: string;
|
|
62
|
+
onSubmit?: OnSubmit;
|
|
63
|
+
} | {
|
|
64
|
+
form: forms.Form;
|
|
65
|
+
onSubmit?: OnSubmit;
|
|
66
|
+
};
|
|
67
|
+
/**
|
|
68
|
+
* Implementation of the Form service that manages reactive form data and submissions.
|
|
69
|
+
* This service provides signals for form data, loading state, error handling, and submission state.
|
|
70
|
+
* It supports both pre-loaded form data and lazy loading with form IDs.
|
|
71
|
+
* Consumers can provide a custom submission handler via config.
|
|
72
|
+
*
|
|
73
|
+
* @example
|
|
74
|
+
* ```tsx
|
|
75
|
+
* // Pre-loaded form data (SSR/SSG)
|
|
76
|
+
* const formService = FormService.withConfig({ form: formData });
|
|
77
|
+
*
|
|
78
|
+
* // Lazy loading with form ID (client-side)
|
|
79
|
+
* const formService = FormService.withConfig({ formId: 'form-123' });
|
|
80
|
+
*
|
|
81
|
+
* // With custom submission handler
|
|
82
|
+
* const formService = FormService.withConfig({
|
|
83
|
+
* formId: 'form-123',
|
|
84
|
+
* onSubmit: async (formId, formValues) => {
|
|
85
|
+
* // Custom submission logic
|
|
86
|
+
* await fetch('/api/submit', { method: 'POST', body: JSON.stringify({ formId, ...formValues }) });
|
|
87
|
+
* return { type: 'success', message: 'Form submitted!' };
|
|
88
|
+
* }
|
|
89
|
+
* });
|
|
90
|
+
* ```
|
|
91
|
+
*/
|
|
92
|
+
export declare const FormService: import("@wix/services-definitions").ServiceFactory<string & {
|
|
93
|
+
__api: FormServiceAPI;
|
|
94
|
+
__config: {};
|
|
95
|
+
isServiceDefinition?: boolean;
|
|
96
|
+
} & FormServiceAPI, FormServiceConfig>;
|
|
97
|
+
/**
|
|
98
|
+
* Loads form service configuration from the Wix Forms API for SSR initialization.
|
|
99
|
+
* This function is designed to be used during Server-Side Rendering (SSR) to preload
|
|
100
|
+
* a specific form by ID that will be used to configure the FormService.
|
|
101
|
+
*
|
|
102
|
+
* @param {string} formId - The unique identifier of the form to load
|
|
103
|
+
* @returns {Promise<FormServiceConfig>} Configuration object with pre-loaded form data
|
|
104
|
+
* @throws {Error} When the form cannot be loaded
|
|
105
|
+
*
|
|
106
|
+
* @example
|
|
107
|
+
* ```tsx
|
|
108
|
+
* // In your SSR/SSG setup
|
|
109
|
+
* const formConfig = await loadFormServiceConfig('form-123');
|
|
110
|
+
* const formService = FormService.withConfig(formConfig);
|
|
111
|
+
* ```
|
|
112
|
+
*/
|
|
113
|
+
export declare function loadFormServiceConfig(formId: string): Promise<FormServiceConfig>;
|
|
114
|
+
export {};
|
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
import { forms, submissions } from '@wix/forms';
|
|
2
|
+
import { defineService, implementService } from '@wix/services-definitions';
|
|
3
|
+
import { SignalsServiceDefinition, } from '@wix/services-definitions/core-services/signals';
|
|
4
|
+
/**
|
|
5
|
+
* Service definition for the Form service.
|
|
6
|
+
* This defines the contract that the FormService must implement.
|
|
7
|
+
*
|
|
8
|
+
* @constant
|
|
9
|
+
*/
|
|
10
|
+
export const FormServiceDefinition = defineService('formService');
|
|
11
|
+
/**
|
|
12
|
+
* Implementation of the Form service that manages reactive form data and submissions.
|
|
13
|
+
* This service provides signals for form data, loading state, error handling, and submission state.
|
|
14
|
+
* It supports both pre-loaded form data and lazy loading with form IDs.
|
|
15
|
+
* Consumers can provide a custom submission handler via config.
|
|
16
|
+
*
|
|
17
|
+
* @example
|
|
18
|
+
* ```tsx
|
|
19
|
+
* // Pre-loaded form data (SSR/SSG)
|
|
20
|
+
* const formService = FormService.withConfig({ form: formData });
|
|
21
|
+
*
|
|
22
|
+
* // Lazy loading with form ID (client-side)
|
|
23
|
+
* const formService = FormService.withConfig({ formId: 'form-123' });
|
|
24
|
+
*
|
|
25
|
+
* // With custom submission handler
|
|
26
|
+
* const formService = FormService.withConfig({
|
|
27
|
+
* formId: 'form-123',
|
|
28
|
+
* onSubmit: async (formId, formValues) => {
|
|
29
|
+
* // Custom submission logic
|
|
30
|
+
* await fetch('/api/submit', { method: 'POST', body: JSON.stringify({ formId, ...formValues }) });
|
|
31
|
+
* return { type: 'success', message: 'Form submitted!' };
|
|
32
|
+
* }
|
|
33
|
+
* });
|
|
34
|
+
* ```
|
|
35
|
+
*/
|
|
36
|
+
export const FormService = implementService.withConfig()(FormServiceDefinition, ({ getService, config }) => {
|
|
37
|
+
const signalsService = getService(SignalsServiceDefinition);
|
|
38
|
+
const isLoadingSignal = signalsService.signal(false);
|
|
39
|
+
const errorSignal = signalsService.signal(null);
|
|
40
|
+
const submitResponseSignal = signalsService.signal({
|
|
41
|
+
type: 'idle',
|
|
42
|
+
});
|
|
43
|
+
const hasSchema = 'form' in config;
|
|
44
|
+
const formSignal = signalsService.signal(hasSchema ? config.form : null);
|
|
45
|
+
if (!hasSchema) {
|
|
46
|
+
loadForm(config.formId);
|
|
47
|
+
}
|
|
48
|
+
async function loadForm(id) {
|
|
49
|
+
isLoadingSignal.set(true);
|
|
50
|
+
errorSignal.set(null);
|
|
51
|
+
try {
|
|
52
|
+
const result = await fetchForm(id);
|
|
53
|
+
if (result) {
|
|
54
|
+
formSignal.set(result);
|
|
55
|
+
}
|
|
56
|
+
else {
|
|
57
|
+
errorSignal.set('Form not found');
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
catch (err) {
|
|
61
|
+
errorSignal.set('Failed to load form');
|
|
62
|
+
throw err;
|
|
63
|
+
}
|
|
64
|
+
finally {
|
|
65
|
+
isLoadingSignal.set(false);
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
async function defaultSubmitHandler(formId, formValues) {
|
|
69
|
+
try {
|
|
70
|
+
await submissions.createSubmission({
|
|
71
|
+
formId,
|
|
72
|
+
submissions: formValues,
|
|
73
|
+
});
|
|
74
|
+
// TODO: add message
|
|
75
|
+
return { type: 'success' };
|
|
76
|
+
}
|
|
77
|
+
catch (error) {
|
|
78
|
+
console.error('Form submission failed:', error);
|
|
79
|
+
return { type: 'error', message: 'Failed to submit form' };
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
/**
|
|
83
|
+
* Submits the form with the provided values.
|
|
84
|
+
* Uses custom handler if provided in config, otherwise uses default submission.
|
|
85
|
+
*/
|
|
86
|
+
async function submitForm(formValues) {
|
|
87
|
+
const form = formSignal.get();
|
|
88
|
+
if (!form) {
|
|
89
|
+
console.error('Cannot submit: form not loaded');
|
|
90
|
+
return;
|
|
91
|
+
}
|
|
92
|
+
// @ts-expect-error
|
|
93
|
+
const formId = form._id ? form._id : form.id;
|
|
94
|
+
submitResponseSignal.set({ type: 'loading' });
|
|
95
|
+
try {
|
|
96
|
+
const handler = config.onSubmit || defaultSubmitHandler;
|
|
97
|
+
const response = await handler(formId, formValues);
|
|
98
|
+
submitResponseSignal.set(response);
|
|
99
|
+
}
|
|
100
|
+
catch (error) {
|
|
101
|
+
console.error('Unexpected error during submission:', error);
|
|
102
|
+
submitResponseSignal.set({
|
|
103
|
+
type: 'error',
|
|
104
|
+
message: 'Unexpected error during submission',
|
|
105
|
+
});
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
return {
|
|
109
|
+
formSignal: formSignal,
|
|
110
|
+
isLoadingSignal: isLoadingSignal,
|
|
111
|
+
errorSignal: errorSignal,
|
|
112
|
+
submitResponseSignal: submitResponseSignal,
|
|
113
|
+
submitForm: submitForm,
|
|
114
|
+
};
|
|
115
|
+
});
|
|
116
|
+
async function fetchForm(id) {
|
|
117
|
+
try {
|
|
118
|
+
const result = await forms.getForm(id);
|
|
119
|
+
if (!result) {
|
|
120
|
+
throw new Error(`Form ${id} not found`);
|
|
121
|
+
}
|
|
122
|
+
return result;
|
|
123
|
+
}
|
|
124
|
+
catch (err) {
|
|
125
|
+
console.error('Failed to load form:', id, err);
|
|
126
|
+
throw err;
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
/**
|
|
130
|
+
* Loads form service configuration from the Wix Forms API for SSR initialization.
|
|
131
|
+
* This function is designed to be used during Server-Side Rendering (SSR) to preload
|
|
132
|
+
* a specific form by ID that will be used to configure the FormService.
|
|
133
|
+
*
|
|
134
|
+
* @param {string} formId - The unique identifier of the form to load
|
|
135
|
+
* @returns {Promise<FormServiceConfig>} Configuration object with pre-loaded form data
|
|
136
|
+
* @throws {Error} When the form cannot be loaded
|
|
137
|
+
*
|
|
138
|
+
* @example
|
|
139
|
+
* ```tsx
|
|
140
|
+
* // In your SSR/SSG setup
|
|
141
|
+
* const formConfig = await loadFormServiceConfig('form-123');
|
|
142
|
+
* const formService = FormService.withConfig(formConfig);
|
|
143
|
+
* ```
|
|
144
|
+
*/
|
|
145
|
+
export async function loadFormServiceConfig(formId) {
|
|
146
|
+
const form = await fetchForm(formId);
|
|
147
|
+
return { form };
|
|
148
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './form-service.js';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './form-service.js';
|
package/package.json
ADDED
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@wix/headless-forms",
|
|
3
|
+
"version": "0.0.0",
|
|
4
|
+
"license": "MIT",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"scripts": {
|
|
7
|
+
"build": "npm run build:esm && npm run build:cjs",
|
|
8
|
+
"build:esm": "tsc -p tsconfig.json",
|
|
9
|
+
"build:cjs": "tsc -p tsconfig.cjs.json",
|
|
10
|
+
"build:watch": "tsc -p tsconfig.json --watch",
|
|
11
|
+
"test": "vitest",
|
|
12
|
+
"lint:fix": "prettier --write \"src/**/*.{ts,tsx,js,jsx,json,md}\"",
|
|
13
|
+
"lint:check": "prettier --check \"src/**/*.{ts,tsx,js,jsx,json,md}\""
|
|
14
|
+
},
|
|
15
|
+
"files": [
|
|
16
|
+
"dist",
|
|
17
|
+
"cjs",
|
|
18
|
+
"react",
|
|
19
|
+
"services"
|
|
20
|
+
],
|
|
21
|
+
"exports": {
|
|
22
|
+
"./react": {
|
|
23
|
+
"types": "./dist/react/index.d.ts",
|
|
24
|
+
"import": "./dist/react/index.js",
|
|
25
|
+
"require": "./cjs/dist/react/index.js"
|
|
26
|
+
},
|
|
27
|
+
"./services": {
|
|
28
|
+
"types": "./dist/services/index.d.ts",
|
|
29
|
+
"import": "./dist/services/index.js",
|
|
30
|
+
"require": "./cjs/dist/services/index.js"
|
|
31
|
+
}
|
|
32
|
+
},
|
|
33
|
+
"devDependencies": {
|
|
34
|
+
"@testing-library/dom": "^10.4.0",
|
|
35
|
+
"@testing-library/jest-dom": "^6.6.3",
|
|
36
|
+
"@testing-library/react": "^16.3.0",
|
|
37
|
+
"@types/node": "^20.9.0",
|
|
38
|
+
"@vitest/ui": "^3.1.4",
|
|
39
|
+
"jsdom": "^26.1.0",
|
|
40
|
+
"prettier": "^3.4.2",
|
|
41
|
+
"typescript": "^5.8.3",
|
|
42
|
+
"vitest": "^3.1.4"
|
|
43
|
+
},
|
|
44
|
+
"dependencies": {
|
|
45
|
+
"@wix/form-public": "^0.55.0",
|
|
46
|
+
"@wix/forms": "^1.0.331",
|
|
47
|
+
"@wix/headless-utils": "0.0.0",
|
|
48
|
+
"@wix/services-definitions": "^0.1.4",
|
|
49
|
+
"@wix/services-manager-react": "^0.1.26"
|
|
50
|
+
},
|
|
51
|
+
"publishConfig": {
|
|
52
|
+
"registry": "https://registry.npmjs.org/",
|
|
53
|
+
"access": "public"
|
|
54
|
+
},
|
|
55
|
+
"wix": {
|
|
56
|
+
"artifact": {
|
|
57
|
+
"artifactId": "headless-forms",
|
|
58
|
+
"groupId": "com.wixpress.headless-components"
|
|
59
|
+
}
|
|
60
|
+
},
|
|
61
|
+
"falconPackageHash": "dcd3156d41c136d87ea0aa02ff35682cef2a377130471163d8530f6d"
|
|
62
|
+
}
|