@teamnovu/nuxt-statamic-formbuilder 0.1.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.
Files changed (40) hide show
  1. package/README.md +13 -0
  2. package/dist/module.d.mts +14 -0
  3. package/dist/module.json +9 -0
  4. package/dist/module.mjs +83 -0
  5. package/dist/runtime/components/FormBuilderFields.d.vue.ts +34 -0
  6. package/dist/runtime/components/FormBuilderFields.vue +86 -0
  7. package/dist/runtime/components/FormBuilderFields.vue.d.ts +34 -0
  8. package/dist/runtime/components/StatamicFormBuilder.d.vue.ts +26 -0
  9. package/dist/runtime/components/StatamicFormBuilder.vue +54 -0
  10. package/dist/runtime/components/StatamicFormBuilder.vue.d.ts +26 -0
  11. package/dist/runtime/composables/useFieldConditions.d.ts +16 -0
  12. package/dist/runtime/composables/useFieldConditions.js +230 -0
  13. package/dist/runtime/composables/useFormBuilder.d.ts +11 -0
  14. package/dist/runtime/composables/useFormBuilder.js +68 -0
  15. package/dist/runtime/composables/useFormFieldRegistry.d.ts +8 -0
  16. package/dist/runtime/composables/useFormFieldRegistry.js +14 -0
  17. package/dist/runtime/composables/useFormValidation.d.ts +11 -0
  18. package/dist/runtime/composables/useFormValidation.js +166 -0
  19. package/dist/runtime/composables/useTranslatableInput.d.ts +8 -0
  20. package/dist/runtime/composables/useTranslatableInput.js +14 -0
  21. package/dist/runtime/fieldConfigs.d.ts +91 -0
  22. package/dist/runtime/fieldConfigs.js +0 -0
  23. package/dist/runtime/injectionKeys.d.ts +6 -0
  24. package/dist/runtime/injectionKeys.js +1 -0
  25. package/dist/runtime/locales/de.json +29 -0
  26. package/dist/runtime/locales/en.json +29 -0
  27. package/dist/runtime/locales/fr.json +29 -0
  28. package/dist/runtime/styles/form-builder.css +1 -0
  29. package/dist/runtime/types.d.ts +126 -0
  30. package/dist/runtime/types.js +22 -0
  31. package/dist/runtime/utils/graphqlFragment.d.ts +5 -0
  32. package/dist/runtime/utils/graphqlFragment.js +37 -0
  33. package/dist/runtime/utils/removePTags.d.ts +1 -0
  34. package/dist/runtime/utils/removePTags.js +4 -0
  35. package/dist/runtime/utils/submitStatamicForm.d.ts +7 -0
  36. package/dist/runtime/utils/submitStatamicForm.js +64 -0
  37. package/dist/runtime/utils/toFormBuilderConfiguration.d.ts +7 -0
  38. package/dist/runtime/utils/toFormBuilderConfiguration.js +37 -0
  39. package/dist/types.d.mts +5 -0
  40. package/package.json +65 -0
@@ -0,0 +1,37 @@
1
+ export const COMPONENT_FORM_BUILDER_FRAGMENT = (
2
+ /* GraphQL */
3
+ `
4
+ fragment ComponentFormBuilder on Fieldset_ComponentFormBuilder {
5
+ __typename
6
+ id
7
+ type
8
+ send_button_text
9
+ form {
10
+ __typename
11
+ handle
12
+ honeypot
13
+ rules
14
+ title
15
+ sections {
16
+ __typename
17
+ display
18
+ instructions
19
+ fields {
20
+ __typename
21
+ config
22
+ display
23
+ handle
24
+ instructions
25
+ type
26
+ width
27
+ if
28
+ unless
29
+ }
30
+ }
31
+ }
32
+ message_loading
33
+ message_success
34
+ message_error
35
+ }
36
+ `
37
+ );
@@ -0,0 +1 @@
1
+ export declare function removePTags(html?: string): string | null;
@@ -0,0 +1,4 @@
1
+ export function removePTags(html) {
2
+ if (!html) return null;
3
+ return html.replace(/<p>|<\/p>/g, "");
4
+ }
@@ -0,0 +1,7 @@
1
+ import type { FormBuilderConfiguration } from '../types.js';
2
+ export declare function submitStatamicForm(args: {
3
+ form: FormBuilderConfiguration;
4
+ state: Record<string, unknown>;
5
+ serverUrl: string;
6
+ locale: string;
7
+ }): Promise<unknown>;
@@ -0,0 +1,64 @@
1
+ const getCookie = (name) => {
2
+ const match = document.cookie.match(
3
+ new RegExp(`(^|;\\s*)(${name})=([^;]*)`)
4
+ );
5
+ return match ? decodeURIComponent(match[3] ?? "") : null;
6
+ };
7
+ function flattenFields(form) {
8
+ if ("fields" in form) {
9
+ return form.fields;
10
+ }
11
+ return form.sections.flatMap((section) => section.fields);
12
+ }
13
+ export async function submitStatamicForm(args) {
14
+ const { form, state, serverUrl, locale } = args;
15
+ if (!serverUrl) {
16
+ throw new Error("[nuxt-statamic-formbuilder] No serverUrl configured for Statamic submit");
17
+ }
18
+ await fetch(`${serverUrl}/sanctum/csrf-cookie`, {
19
+ credentials: "include"
20
+ });
21
+ const token = getCookie("XSRF-TOKEN");
22
+ if (!token) {
23
+ throw new Error("No CSRF token found");
24
+ }
25
+ const formData = new FormData();
26
+ formData.append("_site", locale);
27
+ Object.entries(state).forEach(([key, value]) => {
28
+ if (value?.[0]?.size || value?.[1]?.size) {
29
+ for (let x = 0; x < value.length; x++) {
30
+ formData.append(`${key}[${x}]`, value[x]);
31
+ }
32
+ } else if (value != null) {
33
+ formData.append(key, value);
34
+ }
35
+ });
36
+ flattenFields(form).filter((field) => ["checkboxes", "input_checkboxes"].includes(field.type)).forEach((field) => {
37
+ const copy = [...formData.entries().filter(([key]) => key?.startsWith("["))];
38
+ copy.forEach(([key, value]) => {
39
+ formData.delete(key);
40
+ const newKey = key.replace(`[${field.handle}]`, field.handle);
41
+ formData.append(newKey, value);
42
+ });
43
+ });
44
+ const response = await fetch(
45
+ `${serverUrl}/!/forms/${form.handle}`,
46
+ {
47
+ method: "POST",
48
+ credentials: "include",
49
+ headers: {
50
+ "Accept": "application/json",
51
+ "X-Requested-With": "XMLHttpRequest",
52
+ "X-XSRF-TOKEN": token
53
+ },
54
+ body: formData
55
+ }
56
+ );
57
+ if (!response.ok) {
58
+ const body = await response.json().catch(() => void 0);
59
+ const error = new Error(`HTTP error! status: ${response.status}`);
60
+ error.body = body;
61
+ throw error;
62
+ }
63
+ return await response.json().catch(() => void 0);
64
+ }
@@ -0,0 +1,7 @@
1
+ import type { FormBuilderConfiguration } from '../types.js';
2
+ /**
3
+ * Cast a GraphQL Form payload into FormBuilderConfiguration.
4
+ * Statamic exposes `config` / `rules` as Array scalars — callers typically
5
+ * already receive the right shape after codegen.
6
+ */
7
+ export declare function toFormBuilderConfiguration(form: unknown): FormBuilderConfiguration | undefined;
@@ -0,0 +1,37 @@
1
+ function normalizeField(field) {
2
+ const config = field.config;
3
+ const normalizedConfig = Array.isArray(config) || config == null ? {} : config;
4
+ return {
5
+ ...field,
6
+ config: {
7
+ ...normalizedConfig,
8
+ // Editors often only set Statamic `display`; fieldtype `label` may be empty.
9
+ label: normalizedConfig.label ?? field.display ?? void 0
10
+ }
11
+ };
12
+ }
13
+ export function toFormBuilderConfiguration(form) {
14
+ if (!form || typeof form !== "object") {
15
+ return void 0;
16
+ }
17
+ const candidate = form;
18
+ if (!candidate.handle) {
19
+ return void 0;
20
+ }
21
+ if ("fields" in candidate && Array.isArray(candidate.fields)) {
22
+ return {
23
+ ...form,
24
+ fields: candidate.fields.map(normalizeField)
25
+ };
26
+ }
27
+ if ("sections" in candidate && Array.isArray(candidate.sections)) {
28
+ return {
29
+ ...form,
30
+ sections: candidate.sections.map((section) => ({
31
+ ...section,
32
+ fields: (section.fields ?? []).map(normalizeField)
33
+ }))
34
+ };
35
+ }
36
+ return form;
37
+ }
@@ -0,0 +1,5 @@
1
+ export { type BaseFieldConfig, type DefaultInputField, type DisplayTextFieldConfig, type FormBuilderConfiguration, type FormBuilderField, type FormBuilderFieldBase, type FormBuilderFieldType, type FormBuilderRequestState, type FormBuilderSubmitter, type FormBuilderTexts, type FormFieldOption, type InputCheckboxesFieldConfig, type InputDateFieldConfig, type InputEmailFieldConfig, type InputFileUploadFieldConfig, type InputFormBuilderField, type InputNumberFieldConfig, type InputPhoneFieldConfig, type InputRadioButtonsFieldConfig, type InputRules, type InputSelectFieldConfig, type InputSliderFieldConfig, type InputSwitchFieldConfig, type InputTextFieldConfig, type InputTextareaFieldConfig, type TranslatableInput, type UseFormBuilderOptions, type ValidationTrigger, type defaultInputField, type formBuilderStateKey, type isDisplayOrSpacerField, type isFileUploadField, type isInputField, type isMultiValueField } from '../dist/runtime/types.js'
2
+
3
+ export { default } from './module.mjs'
4
+
5
+ export { type ModuleOptions } from './module.mjs'
package/package.json ADDED
@@ -0,0 +1,65 @@
1
+ {
2
+ "name": "@teamnovu/nuxt-statamic-formbuilder",
3
+ "version": "0.1.0",
4
+ "description": "Headless Nuxt form builder with Statamic submit adapter",
5
+ "license": "MIT",
6
+ "type": "module",
7
+ "exports": {
8
+ ".": {
9
+ "types": "./dist/types.d.mts",
10
+ "import": "./dist/module.mjs"
11
+ },
12
+ "./style.css": "./dist/runtime/styles/form-builder.css",
13
+ "./runtime/*": {
14
+ "types": "./dist/runtime/*.d.ts",
15
+ "import": "./dist/runtime/*"
16
+ },
17
+ "./runtime/types": {
18
+ "types": "./dist/runtime/types.d.ts",
19
+ "import": "./dist/runtime/types.js"
20
+ },
21
+ "./runtime/composables/*": {
22
+ "types": "./dist/runtime/composables/*.d.ts",
23
+ "import": "./dist/runtime/composables/*"
24
+ }
25
+ },
26
+ "main": "./dist/module.mjs",
27
+ "typesVersions": {
28
+ "*": {
29
+ ".": [
30
+ "./dist/types.d.mts"
31
+ ]
32
+ }
33
+ },
34
+ "files": [
35
+ "dist"
36
+ ],
37
+ "publishConfig": {
38
+ "access": "public"
39
+ },
40
+ "dependencies": {
41
+ "@nuxt/kit": "^4.3.1",
42
+ "valibot": "^1.2.0"
43
+ },
44
+ "peerDependencies": {
45
+ "@nuxtjs/i18n": ">=9",
46
+ "nuxt": ">=3.16",
47
+ "vue-i18n": ">=9"
48
+ },
49
+ "devDependencies": {
50
+ "@nuxt/module-builder": "^1.0.2",
51
+ "@nuxt/schema": "^4.3.1",
52
+ "@nuxtjs/i18n": "^10.2.3",
53
+ "@types/node": "^24.11.0",
54
+ "eslint": "^10.0.2",
55
+ "nuxt": "^4.3.1",
56
+ "typescript": "^5.9.3",
57
+ "vue": "^3.5.13",
58
+ "vue-i18n": "^11.4.6",
59
+ "vue-tsc": "^3.3.7"
60
+ },
61
+ "scripts": {
62
+ "dev:prepare": "nuxt-module-build build --stub && nuxt-module-build prepare",
63
+ "lint": "eslint ."
64
+ }
65
+ }