formsync 0.1.0 → 0.1.1
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 +112 -34
- package/dist/index.cjs +2 -0
- package/dist/index.d.cts +29 -0
- package/dist/index.d.ts +29 -0
- package/dist/index.js +2 -0
- package/package.json +39 -11
package/README.md
CHANGED
|
@@ -1,61 +1,139 @@
|
|
|
1
|
-
# FormSync
|
|
1
|
+
# FormSync
|
|
2
2
|
|
|
3
|
-
**
|
|
3
|
+
**FormSync is the easiest way to accept and manage form submissions without building a backend.**
|
|
4
4
|
|
|
5
|
-
FormSync lets
|
|
5
|
+
FormSync lets you submit HTML & React forms directly to **formsync.app** with built-in spam protection, simple callbacks and zero server code.
|
|
6
|
+
|
|
7
|
+
👉 **[https://formsync.app](https://formsync.app)**
|
|
8
|
+
|
|
9
|
+
## Installation
|
|
10
|
+
|
|
11
|
+
```bash
|
|
12
|
+
npm install formsync
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
or
|
|
16
|
+
|
|
17
|
+
```bash
|
|
18
|
+
yarn add formsync
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
---
|
|
22
|
+
|
|
23
|
+
## Create a Form on FormSync
|
|
24
|
+
|
|
25
|
+
1. Go to **[https://formsync.app](https://formsync.app)**
|
|
26
|
+
2. Create a new form
|
|
27
|
+
3. Copy your **Form ID**
|
|
28
|
+
|
|
29
|
+
You’ll need this `formId` to submit data.
|
|
6
30
|
|
|
7
31
|
---
|
|
8
32
|
|
|
9
|
-
##
|
|
33
|
+
## Basic Usage
|
|
10
34
|
|
|
11
|
-
|
|
35
|
+
```tsx
|
|
36
|
+
import { FormSyncForm } from "formsync";
|
|
12
37
|
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
38
|
+
<FormSyncForm formId="YOUR_FORM_ID">
|
|
39
|
+
<input name="email" />
|
|
40
|
+
<button type="submit">Submit</button>
|
|
41
|
+
</FormSyncForm>
|
|
42
|
+
```
|
|
17
43
|
|
|
18
|
-
|
|
44
|
+
That’s it.
|
|
45
|
+
No backend. No API routes.
|
|
19
46
|
|
|
20
47
|
---
|
|
21
48
|
|
|
22
|
-
##
|
|
49
|
+
## With Success & Error Handling
|
|
23
50
|
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
51
|
+
```tsx
|
|
52
|
+
import { FormSyncForm } from "formsync";
|
|
53
|
+
|
|
54
|
+
<FormSyncForm
|
|
55
|
+
formId="YOUR_FORM_ID"
|
|
56
|
+
onSuccess={(res) => console.log("Success:", res)}
|
|
57
|
+
onSubmitError={(err) => console.error("Error:", err)}
|
|
58
|
+
>
|
|
59
|
+
<input name="email" />
|
|
60
|
+
<button type="submit">Submit</button>
|
|
61
|
+
</FormSyncForm>
|
|
62
|
+
```
|
|
30
63
|
|
|
31
64
|
---
|
|
32
65
|
|
|
33
|
-
##
|
|
66
|
+
## Using the FormSync Button (Recommended)
|
|
67
|
+
|
|
68
|
+
FormSync provides a **special submit button** that automatically shows loading state.
|
|
34
69
|
|
|
35
|
-
|
|
70
|
+
```tsx
|
|
71
|
+
import { FormSyncForm, FormSyncButton } from "formsync";
|
|
72
|
+
|
|
73
|
+
<FormSyncForm formId="YOUR_FORM_ID">
|
|
74
|
+
<input name="email" />
|
|
75
|
+
|
|
76
|
+
<FormSyncButton>
|
|
77
|
+
Submit
|
|
78
|
+
</FormSyncButton>
|
|
79
|
+
</FormSyncForm>
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
### Default behavior
|
|
83
|
+
|
|
84
|
+
* Shows **“Submit”**
|
|
85
|
+
* On submit → shows **“Submitting…”**
|
|
86
|
+
* Button auto-disables while submitting
|
|
87
|
+
|
|
88
|
+
---
|
|
89
|
+
|
|
90
|
+
## Spam Protection
|
|
91
|
+
|
|
92
|
+
FormSync automatically injects a hidden honeypot field:
|
|
36
93
|
|
|
37
94
|
```html
|
|
38
|
-
<
|
|
39
|
-
<input type="text" name="name" placeholder="Your Name" required />
|
|
40
|
-
<input type="email" name="email" placeholder="Your Email" required />
|
|
41
|
-
<button type="submit">Send</button>
|
|
42
|
-
</form>
|
|
95
|
+
<input type="text" name="_fs_hp" hidden />
|
|
43
96
|
```
|
|
44
97
|
|
|
45
|
-
|
|
98
|
+
Bots fill it → submissions are ignored.
|
|
99
|
+
Humans never see it.
|
|
46
100
|
|
|
47
|
-
|
|
101
|
+
---
|
|
48
102
|
|
|
49
|
-
|
|
50
|
-
Whether you’re building a static site, a Next.js app, or a quick prototype — FormSync keeps your workflow lightweight and efficient.
|
|
103
|
+
## 🧩 Works With
|
|
51
104
|
|
|
52
|
-
|
|
105
|
+
* React
|
|
106
|
+
* Next.js (App Router & Pages Router)
|
|
107
|
+
* Vite
|
|
108
|
+
* CRA
|
|
109
|
+
* Remix (client side)
|
|
53
110
|
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
111
|
+
---
|
|
112
|
+
|
|
113
|
+
## API Reference
|
|
114
|
+
|
|
115
|
+
### `<FormSyncForm />`
|
|
116
|
+
|
|
117
|
+
| Prop | Type | Description |
|
|
118
|
+
| --------------- | --------------- | -------------------------------------- |
|
|
119
|
+
| `formId` | `string` | **Required** Form ID from formsync.app |
|
|
120
|
+
| `onSuccess` | `(res) => void` | Called on successful submission |
|
|
121
|
+
| `onSubmitError` | `(err) => void` | Called on failed submission |
|
|
122
|
+
| `...props` | `form props` | All native `<form>` attributes |
|
|
123
|
+
|
|
124
|
+
---
|
|
125
|
+
|
|
126
|
+
### `<FormSyncButton />`
|
|
127
|
+
|
|
128
|
+
| Feature | Supported |
|
|
129
|
+
| ------------------ | --------- |
|
|
130
|
+
| Loading state | yes |
|
|
131
|
+
| Disabled on submit | yes |
|
|
132
|
+
| Custom UI | yes |
|
|
133
|
+
| Optional usage | yes |
|
|
58
134
|
|
|
59
135
|
---
|
|
60
136
|
|
|
61
|
-
|
|
137
|
+
## Links
|
|
138
|
+
|
|
139
|
+
Website: [https://formsync.app](https://formsync.app)
|
package/dist/index.cjs
ADDED
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
"use strict";var a=Object.defineProperty;var v=Object.getOwnPropertyDescriptor;var C=Object.getOwnPropertyNames;var b=Object.prototype.hasOwnProperty;var h=(o,t)=>{for(var e in t)a(o,e,{get:t[e],enumerable:!0})},P=(o,t,e,n)=>{if(t&&typeof t=="object"||typeof t=="function")for(let r of C(t))!b.call(o,r)&&r!==e&&a(o,r,{get:()=>t[r],enumerable:!(n=v(t,r))||n.enumerable});return o};var g=o=>P(a({},"__esModule",{value:!0}),o);var L={};h(L,{FormSyncButton:()=>T,FormSyncForm:()=>w});module.exports=g(L);var c=require("react"),S=require("react/jsx-runtime"),y=(0,c.createContext)(void 0),f=({children:o})=>{let[t,e]=(0,c.useState)(!1);return(0,S.jsx)(y.Provider,{value:{loading:t,setLoading:e},children:o})},s=()=>{let o=(0,c.useContext)(y);if(!o)throw new Error("useFormSyncContext must be used within FormSyncContextProvider");return o};var m=require("react/jsx-runtime");function R({formId:o,onSuccess:t,onSubmitError:e,children:n,...r}){let{setLoading:u}=s();return(0,m.jsxs)("form",{onSubmit:async d=>{d.preventDefault();let F=d.currentTarget,x=new FormData(F);try{u(!0);let i=await fetch(`http://localhost:8000/v1/s/${o}`,{method:"POST",body:x,headers:{Accept:"application/json"}}),p=await i.json();i.ok?t?.(p):e?.(p),i.ok&&F.reset()}catch{e?.({success:!1,message:"Network error"})}finally{u(!1)}},...r,children:[n,(0,m.jsx)("input",{type:"text",name:"_fs_hp",hidden:!0})]})}function w({...o}){return(0,m.jsx)(f,{children:(0,m.jsx)(R,{...o})})}var l=require("react/jsx-runtime");function T({loadingText:o,children:t,...e}){let{loading:n}=s();return(0,l.jsx)("button",{type:"submit",disabled:n,...e,children:n?o||"Submitting...":t})}0&&(module.exports={FormSyncButton,FormSyncForm});
|
package/dist/index.d.cts
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
2
|
+
import React$1, { ButtonHTMLAttributes } from 'react';
|
|
3
|
+
|
|
4
|
+
type FormSyncSuccess = {
|
|
5
|
+
success: true;
|
|
6
|
+
submissionId: string;
|
|
7
|
+
message?: string;
|
|
8
|
+
};
|
|
9
|
+
type FormSyncError = {
|
|
10
|
+
success: false;
|
|
11
|
+
message: string;
|
|
12
|
+
fieldErrors?: Record<string, string>;
|
|
13
|
+
};
|
|
14
|
+
type FormSyncResponse = FormSyncSuccess | FormSyncError;
|
|
15
|
+
interface FormSyncButtonProps extends ButtonHTMLAttributes<HTMLButtonElement> {
|
|
16
|
+
loadingText?: string;
|
|
17
|
+
children: React.ReactNode;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
interface FormSyncFormProps extends React$1.FormHTMLAttributes<HTMLFormElement> {
|
|
21
|
+
formId: string;
|
|
22
|
+
onSuccess?: (res: FormSyncResponse) => void;
|
|
23
|
+
onSubmitError?: (err: FormSyncResponse) => void;
|
|
24
|
+
}
|
|
25
|
+
declare function FormSyncForm({ ...props }: FormSyncFormProps): react_jsx_runtime.JSX.Element;
|
|
26
|
+
|
|
27
|
+
declare function FormSyncButton({ loadingText, children, ...props }: FormSyncButtonProps): react_jsx_runtime.JSX.Element;
|
|
28
|
+
|
|
29
|
+
export { FormSyncButton, type FormSyncButtonProps, type FormSyncError, FormSyncForm, type FormSyncResponse, type FormSyncSuccess };
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
2
|
+
import React$1, { ButtonHTMLAttributes } from 'react';
|
|
3
|
+
|
|
4
|
+
type FormSyncSuccess = {
|
|
5
|
+
success: true;
|
|
6
|
+
submissionId: string;
|
|
7
|
+
message?: string;
|
|
8
|
+
};
|
|
9
|
+
type FormSyncError = {
|
|
10
|
+
success: false;
|
|
11
|
+
message: string;
|
|
12
|
+
fieldErrors?: Record<string, string>;
|
|
13
|
+
};
|
|
14
|
+
type FormSyncResponse = FormSyncSuccess | FormSyncError;
|
|
15
|
+
interface FormSyncButtonProps extends ButtonHTMLAttributes<HTMLButtonElement> {
|
|
16
|
+
loadingText?: string;
|
|
17
|
+
children: React.ReactNode;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
interface FormSyncFormProps extends React$1.FormHTMLAttributes<HTMLFormElement> {
|
|
21
|
+
formId: string;
|
|
22
|
+
onSuccess?: (res: FormSyncResponse) => void;
|
|
23
|
+
onSubmitError?: (err: FormSyncResponse) => void;
|
|
24
|
+
}
|
|
25
|
+
declare function FormSyncForm({ ...props }: FormSyncFormProps): react_jsx_runtime.JSX.Element;
|
|
26
|
+
|
|
27
|
+
declare function FormSyncButton({ loadingText, children, ...props }: FormSyncButtonProps): react_jsx_runtime.JSX.Element;
|
|
28
|
+
|
|
29
|
+
export { FormSyncButton, type FormSyncButtonProps, type FormSyncError, FormSyncForm, type FormSyncResponse, type FormSyncSuccess };
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import{createContext as f,useContext as S,useState as l}from"react";import{jsx as x}from"react/jsx-runtime";var d=f(void 0),F=({children:o})=>{let[e,t]=l(!1);return x(d.Provider,{value:{loading:e,setLoading:t},children:o})},r=()=>{let o=S(d);if(!o)throw new Error("useFormSyncContext must be used within FormSyncContextProvider");return o};import{jsx as m,jsxs as C}from"react/jsx-runtime";function v({formId:o,onSuccess:e,onSubmitError:t,children:n,...p}){let{setLoading:s}=r();return C("form",{onSubmit:async i=>{i.preventDefault();let a=i.currentTarget,y=new FormData(a);try{s(!0);let c=await fetch(`http://localhost:8000/v1/s/${o}`,{method:"POST",body:y,headers:{Accept:"application/json"}}),u=await c.json();c.ok?e?.(u):t?.(u),c.ok&&a.reset()}catch{t?.({success:!1,message:"Network error"})}finally{s(!1)}},...p,children:[n,m("input",{type:"text",name:"_fs_hp",hidden:!0})]})}function L({...o}){return m(F,{children:m(v,{...o})})}import{jsx as b}from"react/jsx-runtime";function D({loadingText:o,children:e,...t}){let{loading:n}=r();return b("button",{type:"submit",disabled:n,...t,children:n?o||"Submitting...":e})}export{D as FormSyncButton,L as FormSyncForm};
|
package/package.json
CHANGED
|
@@ -1,21 +1,49 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "formsync",
|
|
3
|
-
"version": "0.1.
|
|
4
|
-
"description": "
|
|
5
|
-
"
|
|
3
|
+
"version": "0.1.1",
|
|
4
|
+
"description": "The Easiest Way to Accept Form Submissions",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"formsync",
|
|
7
|
+
"react",
|
|
8
|
+
"nextjs",
|
|
9
|
+
"forms",
|
|
10
|
+
"saas",
|
|
11
|
+
"form-handler"
|
|
12
|
+
],
|
|
13
|
+
"main": "dist/index.js",
|
|
14
|
+
"module": "dist/index.mjs",
|
|
15
|
+
"types": "dist/index.d.ts",
|
|
16
|
+
"exports": {
|
|
17
|
+
".": {
|
|
18
|
+
"import": "./dist/index.js",
|
|
19
|
+
"require": "./dist/index.mjs"
|
|
20
|
+
}
|
|
21
|
+
},
|
|
22
|
+
"files": [
|
|
23
|
+
"dist"
|
|
24
|
+
],
|
|
6
25
|
"scripts": {
|
|
7
|
-
"
|
|
26
|
+
"build": "tsup",
|
|
27
|
+
"dev": "tsup --watch"
|
|
28
|
+
},
|
|
29
|
+
"peerDependencies": {
|
|
30
|
+
"react": ">=17"
|
|
8
31
|
},
|
|
32
|
+
"devDependencies": {
|
|
33
|
+
"@types/react": "^19.2.7",
|
|
34
|
+
"react": "^18.2.0",
|
|
35
|
+
"tsup": "^8.0.1",
|
|
36
|
+
"typescript": "^5.3.0"
|
|
37
|
+
},
|
|
38
|
+
"author": "FormSync",
|
|
39
|
+
"license": "MIT",
|
|
40
|
+
"type": "module",
|
|
9
41
|
"repository": {
|
|
10
42
|
"type": "git",
|
|
11
|
-
"url": "
|
|
43
|
+
"url": "https://github.com/sudhucodes/formsync.git"
|
|
12
44
|
},
|
|
13
|
-
"
|
|
14
|
-
"author": "",
|
|
15
|
-
"license": "ISC",
|
|
16
|
-
"type": "commonjs",
|
|
45
|
+
"homepage": "https://formsync.app",
|
|
17
46
|
"bugs": {
|
|
18
47
|
"url": "https://github.com/sudhucodes/formsync/issues"
|
|
19
|
-
}
|
|
20
|
-
"homepage": "https://github.com/sudhucodes/formsync#readme"
|
|
48
|
+
}
|
|
21
49
|
}
|