{"id":20239983,"url":"https://github.com/thavarshan/formlink","last_synced_at":"2025-04-10T19:50:25.446Z","repository":{"id":258457431,"uuid":"694123312","full_name":"Thavarshan/formlink","owner":"Thavarshan","description":"⛓️‍💥 The source code of Formlink. A Fullstack TypeScript form handler library.","archived":false,"fork":false,"pushed_at":"2024-11-15T07:03:39.000Z","size":2572,"stargazers_count":9,"open_issues_count":1,"forks_count":2,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-04-03T14:39:27.342Z","etag":null,"topics":["form","formlink","formlinkjs","fullstack","source","source-code","typescript","typescript-library"],"latest_commit_sha":null,"homepage":"https://thavarshan.com","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/Thavarshan.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":".github/CONTRIBUTING.md","funding":".github/FUNDING.yml","license":"LICENSE","code_of_conduct":".github/CODE_OF_CONDUCT.md","threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":".github/SECURITY.md","support":".github/SUPPORT.md","governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null},"funding":{"github":"thavarshan","buy_me_a_coffee":"thavarshan"}},"created_at":"2023-09-20T11:28:23.000Z","updated_at":"2025-03-30T08:14:11.000Z","dependencies_parsed_at":"2024-12-27T12:36:56.150Z","dependency_job_id":"5d9aca7a-914b-467d-a567-1624e1cdd80e","html_url":"https://github.com/Thavarshan/formlink","commit_stats":{"total_commits":109,"total_committers":4,"mean_commits":27.25,"dds":"0.37614678899082565","last_synced_commit":"26e5e02a98c73f64ccb2277fa1945ceeb19cb86d"},"previous_names":["thavarshan/formlink"],"tags_count":12,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Thavarshan%2Fformlink","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Thavarshan%2Fformlink/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Thavarshan%2Fformlink/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Thavarshan%2Fformlink/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/Thavarshan","download_url":"https://codeload.github.com/Thavarshan/formlink/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248282925,"owners_count":21077736,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["form","formlink","formlinkjs","fullstack","source","source-code","typescript","typescript-library"],"created_at":"2024-11-14T08:42:31.581Z","updated_at":"2025-04-10T19:50:25.438Z","avatar_url":"https://github.com/Thavarshan.png","language":"TypeScript","funding_links":["https://github.com/sponsors/thavarshan","https://buymeacoffee.com/thavarshan"],"categories":[],"sub_categories":[],"readme":"[![Formlink](./assets/Banner.png)](https://github.com/Thavarshan/formlink)\n\n# Formlink\n\n[![Latest Version on npm](https://img.shields.io/npm/v/formlink.svg)](https://www.npmjs.com/package/formlink)\n[![Test](https://github.com/Thavarshan/formlink/actions/workflows/test.yml/badge.svg)](https://github.com/Thavarshan/formlink/actions/workflows/test.yml)\n[![Lint](https://github.com/Thavarshan/formlink/actions/workflows/lint.yml/badge.svg)](https://github.com/Thavarshan/formlink/actions/workflows/lint.yml)\n[![Total Downloads](https://img.shields.io/npm/dt/formlink.svg)](https://www.npmjs.com/package/formlink)\n[![TypeScript](https://img.shields.io/badge/TypeScript-Ready-blue.svg)](https://www.typescriptlang.org/)\n[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)\n\nFormlink is a type-safe form-handling library for Laravel + Vue.js applications. It abstracts away form submissions, file uploads, and validation error handling, offering seamless integration with Laravel and Vue.js applications, inspired by Inertia.js's simplicity.\n\n## Features\n\n- ✨ **Type Safety**: Full TypeScript support with type inference\n- 🚀 **Zero Configuration**: Works out of the box with Laravel\n- 🔐 **Built-in CSRF Protection**: Automatic CSRF token handling\n- 🔄 **Progress Tracking**: Real-time file upload progress\n- 🎯 **Smart Error Handling**: Automatic Laravel validation error management\n- ⚡ **Event Hooks**: Rich lifecycle hooks for form submission events\n- 📱 **Vue 3 Ready**: Reactive forms with Vue 3 composition API\n- 🛠️ **Framework Agnostic**: Can be used with any backend, not limited to Laravel\n- 🔀 **HTTP Method Support**: Comprehensive support for all HTTP methods\n- 🧹 **Form Reset \u0026 State Management**: Easily reset form data to initial state\n- 🔄 **Debounced Submissions**: Support for debounced form submissions\n\n## Quick Start\n\n### Installation\n\n```bash\nnpm install formlink\n# or\nyarn add formlink\n# or\npnpm add formlink\n```\n\n### Basic Usage\n\n```typescript\nimport { useForm } from 'formlink';\n\ninterface ContactForm {\n  name: string;\n  email: string;\n  message: string;\n}\n\nconst form = useForm\u003cContactForm\u003e({\n  name: '',\n  email: '',\n  message: ''\n});\n\nawait form.post('/api/contact');\n```\n\n### Complete Example\n\n```vue\n\u003ctemplate\u003e\n  \u003cform @submit.prevent=\"submit\"\u003e\n    \u003c!-- Name field --\u003e\n    \u003cdiv\u003e\n      \u003cinput v-model=\"form.name\" type=\"text\" :class=\"{ error: form.errors.name }\" /\u003e\n      \u003cspan v-if=\"form.errors.name\"\u003e{{ form.errors.name }}\u003c/span\u003e\n    \u003c/div\u003e\n\n    \u003c!-- Email field --\u003e\n    \u003cdiv\u003e\n      \u003cinput v-model=\"form.email\" type=\"email\" :class=\"{ error: form.errors.email }\" /\u003e\n      \u003cspan v-if=\"form.errors.email\"\u003e{{ form.errors.email }}\u003c/span\u003e\n    \u003c/div\u003e\n\n    \u003c!-- File upload with progress --\u003e\n    \u003cdiv\u003e\n      \u003cinput type=\"file\" @change=\"handleFile\" /\u003e\n      \u003cdiv v-if=\"form.progress\"\u003e{{ form.progress.percentage }}% uploaded\u003c/div\u003e\n    \u003c/div\u003e\n\n    \u003c!-- Submit button --\u003e\n    \u003cbutton type=\"submit\" :disabled=\"form.processing\"\u003e\n      {{ form.processing ? 'Sending...' : 'Send Message' }}\n    \u003c/button\u003e\n  \u003c/form\u003e\n\u003c/template\u003e\n\n\u003cscript setup lang=\"ts\"\u003e\nimport { useForm } from 'formlink';\n\ninterface ContactForm {\n  name: string;\n  email: string;\n  file: File | null;\n}\n\nconst form = useForm\u003cContactForm\u003e({\n  name: '',\n  email: '',\n  file: null\n});\n\nconst handleFile = (e: Event) =\u003e {\n  const file = (e.target as HTMLInputElement).files?.[0];\n  if (file) {\n    form.file = file;\n  }\n};\n\nconst submit = async () =\u003e {\n  await form.post('/api/contact', {\n    onBefore: () =\u003e {\n      console.log('Request starting');\n    },\n    onProgress: (progress) =\u003e {\n      console.log(`${progress.percentage}% uploaded`);\n    },\n    onSuccess: (response) =\u003e {\n      console.log('Submission successful', response.data);\n    },\n    onError: (errors) =\u003e {\n      console.log('Validation errors', errors);\n    },\n    onFinish: () =\u003e {\n      console.log('Request finished');\n    }\n  });\n};\n\u003c/script\u003e\n```\n\n## Available `FormOptions`\n\nThe `FormOptions` object allows you to configure hooks and behaviors for form submissions. Here are the available options:\n\n| Option         | Type                                         | Description                                                                 |\n|----------------|----------------------------------------------|-----------------------------------------------------------------------------|\n| `resetOnSuccess` | `boolean`                                   | Whether to reset the form to its initial state after a successful submission. |\n| `onBefore`      | `() =\u003e void`                                 | Hook that is called before the form submission begins.                      |\n| `onSuccess`     | `(response: AxiosResponse) =\u003e void`          | Hook that is called when the form submission is successful.                 |\n| `onCanceled`    | `() =\u003e void`                                 | Hook that is called when the form submission is canceled.                   |\n| `onError`       | `(errors: Partial\u003cRecord\u003ckeyof TForm, string\u003e\u003e)` | Hook that is called when validation errors occur (e.g., from a Laravel backend). |\n| `onFinish`      | `() =\u003e void`                                 | Hook that is called when the form submission finishes, whether successful or not. |\n| `onProgress`    | `(progress: Progress) =\u003e void`               | Hook that tracks file upload progress or long-running requests.             |\n\n### Example of Form Options\n\n```typescript\nawait form.post('/api/contact', {\n  resetOnSuccess: true,\n  onBefore: () =\u003e console.log('Submitting...'),\n  onSuccess: (response) =\u003e console.log('Submitted', response.data),\n  onError: (errors) =\u003e console.error('Validation errors:', errors),\n  onFinish: () =\u003e console.log('Request finished'),\n  onProgress: (progress) =\u003e console.log(`Upload ${progress.percentage}% complete`),\n});\n```\n\n## Advanced Features\n\n### Form States\n\nFormlink provides various reactive states:\n\n```typescript\nform.processing;         // Is the form being submitted?\nform.progress;           // Upload progress data\nform.errors;             // Validation errors\nform.isDirty;            // Has the form been modified?\nform.wasSuccessful;      // Was the form submission successful?\nform.recentlySuccessful; // Was the form submission successful recently?\n```\n\n### HTTP Methods\n\nFormlink supports multiple HTTP methods:\n\n```typescript\nform.get(url);     // GET request\nform.post(url);    // POST request\nform.put(url);     // PUT request\nform.patch(url);   // PATCH request\nform.delete(url);  // DELETE request\nform.options(url); // OPTIONS request\n```\n\n### Data Transformation\n\nYou can transform form data before it is submitted:\n\n```typescript\nform.transform((data) =\u003e ({\n  ...data,\n  name: data.name.trim().toLowerCase()\n}));\n```\n\n### Error Handling\n\nSet or clear errors manually:\n\n```typescript\n// Set a single error\nform.setError('email', 'Invalid email format');\n\n// Set multiple errors at once\nform.setErrors({\n  email: 'Invalid email format',\n  name: 'Name is required',\n  formError: 'Please fix the errors before submitting'\n});\n\n// Clear all errors\nform.clearErrors();\n```\n\n### Reset Functionality\n\nReset the form data to its initial state:\n\n```typescript\n// Reset all fields\nform.reset();\n\n// Reset specific fields\nform.reset('email', 'name');\n```\n\n### Default Values\n\nSet new default values for the form:\n\n```typescript\n// Set all current data as new defaults\nform.setDefaults();\n\n// Set a specific field's default value\nform.setDefaults('email', 'default@example.com');\n\n// Set multiple field defaults at once\nform.setDefaults({\n  name: 'John Doe',\n  email: 'john@example.com'\n});\n```\n\n### Validation\n\nFormlink provides a simple validation system:\n\n```typescript\n// Define validation rules\nform.rules = {\n  email: [\n    { validate: (value) =\u003e !!value, message: 'Email is required' },\n    { validate: (value) =\u003e /\\S+@\\S+\\.\\S+/.test(value as string), message: 'Invalid email format' }\n  ],\n  name: [\n    { validate: (value) =\u003e !!value, message: 'Name is required' }\n  ]\n};\n\n// Run validation\nconst isValid = await form.validate();\nif (isValid) {\n  await form.post('/api/contact');\n}\n```\n\n### Debounced Submissions\n\nFor search forms or auto-save functionality:\n\n```typescript\n// Debounce form submission (default 300ms)\nform.submitDebounced('get', '/api/search');\n\n// Custom debounce time (1000ms)\nform.submitDebounced('post', '/api/auto-save', {}, 1000);\n```\n\n### Cancellation\n\nCancel an ongoing form submission:\n\n```typescript\n// Start submission\nconst submissionPromise = form.post('/api/upload-large-file');\n\n// Cancel it if needed\nform.cancel();\n```\n\n### Custom Axios Instance\n\nYou can use a custom Axios instance for your form requests:\n\n```typescript\nimport axios from 'axios';\n\nconst customAxios = axios.create({\n  baseURL: 'https://api.example.com',\n  timeout: 5000,\n  headers: {\n    'X-Custom-Header': 'value'\n  }\n});\n\nconst form = useForm(data, customAxios);\n```\n\n### Resource Cleanup\n\nFor single-page applications, ensure proper cleanup:\n\n```typescript\n// In your component's onUnmounted lifecycle hook\nonUnmounted(() =\u003e {\n  form.dispose();\n});\n```\n\n## Contributing\n\nContributions are welcome! See our [Contributing Guide](https://github.com/Thavarshan/formlink/blob/main/.github/CONTRIBUTING.md) for details.\n\nTo get started:\n\n1. Fork the repository.\n2. Create your feature branch (`git checkout -b feature/your-feature`).\n3. Commit your changes (`git commit -m 'Add feature'`).\n4. Push to your branch (`git push origin feature/your-feature`).\n5. Open a pull request.\n\n### Development Setup\n\n```bash\n# Clone the repository\ngit clone https://github.com/Thavarshan/formlink.git\n\n# Install dependencies\nnpm install\n\n# Run tests\nnpm test\n\n# Build the package\nnpm run build\n```\n\n## License\n\nFormlink is open-sourced software licensed under the [MIT license](LICENSE.md).\n\n## Acknowledgments\n\nSpecial thanks to [**Jonathan Reinink**](https://github.com/reinink) for his work on [**InertiaJS**](https://inertiajs.com/), which inspired this project.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fthavarshan%2Fformlink","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fthavarshan%2Fformlink","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fthavarshan%2Fformlink/lists"}