{"id":13496193,"url":"https://github.com/tehSLy/efform","last_synced_at":"2025-03-28T18:31:44.956Z","repository":{"id":40753144,"uuid":"281945460","full_name":"tehSLy/efform","owner":"tehSLy","description":"Form manager, based on effector state manager, designed to deliver high-quality DX","archived":false,"fork":false,"pushed_at":"2023-03-05T12:33:08.000Z","size":1290,"stargazers_count":12,"open_issues_count":29,"forks_count":1,"subscribers_count":1,"default_branch":"dev","last_synced_at":"2024-04-25T23:22:11.490Z","etag":null,"topics":["effector","forms","state-management"],"latest_commit_sha":null,"homepage":"","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/tehSLy.png","metadata":{"files":{"readme":"README.MD","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null}},"created_at":"2020-07-23T12:28:57.000Z","updated_at":"2023-11-24T08:49:25.000Z","dependencies_parsed_at":"2024-01-07T18:24:56.204Z","dependency_job_id":null,"html_url":"https://github.com/tehSLy/efform","commit_stats":{"total_commits":39,"total_committers":1,"mean_commits":39.0,"dds":0.0,"last_synced_commit":"ba87f2a8f776db044adee45ee7ff76f195605f49"},"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tehSLy%2Fefform","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tehSLy%2Fefform/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tehSLy%2Fefform/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tehSLy%2Fefform/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/tehSLy","download_url":"https://codeload.github.com/tehSLy/efform/tar.gz/refs/heads/dev","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":222403043,"owners_count":16978781,"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":["effector","forms","state-management"],"created_at":"2024-07-31T19:01:43.631Z","updated_at":"2024-10-31T11:31:01.844Z","avatar_url":"https://github.com/tehSLy.png","language":"TypeScript","funding_links":[],"categories":["TypeScript","Packages"],"sub_categories":["Form management"],"readme":"# EFFORM\n\nForm manager, based on `effector` state manager, designed to deliver high-quality DX\n\n## Installation  \n\nSimply execute `npm i efform` in the terminal.  \n**Notice**: efform uses `effector` as a peer dependency, so if you don't have this package installed, install it by yourself\n\n## Usage \u0026 Basics\n\n```ts\nimport { createForm, string, number } from \"efform\";\nimport { forward, createEffect } from \"effector\";\n\nconst fxSendForm = createEffect({ handler: console.log });\n\nconst form = createForm({\n  name: string().required(),\n  age: number(18).max(100),\n  email: string().required().pattern(/.+@.+/),\n});\n\nforward({ from: form.submitted, to: fxSendForm });\nform.submit();\n// =\u003e {name: \"\", age: 18, email: \"\"}\n```\n\nIn efform, **Forms** may consist of nested **Forms**, nested **Inline-Forms**, or **Fields**\n\n### Form\n\nThis is the very common type of unit. It defines structure of data-slice, with validation, error and state management included. \n```ts\ntype Form\u003cT\u003e = {\n  submit: Event\u003cvoid\u003e;\n  submitted: Event\u003cT\u003e;\n\n  set: Event\u003c{key: K; payload: T[K]\u003e;\n  setErrors: Event\u003cErrors\u003cT\u003e\u003e;\n  fill: Event\u003cValues\u003cPartial\u003cT\u003e\u003e\u003e;\n  validate: Effect\u003cvoid, any, Error\u003e;\n\n  values: Store\u003cT\u003e;\n  errors: Store\u003cErrors\u003cT\u003e\u003e;\n  validateField: Effect\u003ckeyof T, any, Error\u003e;\n\n  isValid: Store\u003cboolean\u003e\n  \n  fields: Record\u003ckeyof T, Field\u003e\n  getMeta(): FormMeta\u003cT\u003e;\n}\n```\n\nSee example of basic form on following snippet:\n\n```ts\nconst form = createForm({\n  age: number(),\n  name: string(),\n});\n```\n\n### Nested Forms\n\nIt might be either dedicated, or inline-forms. Dedicated forms - are just forms, declared outside of parent, see example below:\n\n```ts\nconst nestedForm = createForm({\n  name: string(),\n  age: number(),\n});\n\nconst form = createForm({\n  // Notice, how nested form is used here, as a part of the main one\n  bio: nestedForm,\n  status: string(),\n});\n```\n\nAside from being basically a simple form, being child form provides us opportunity to manage it's state by it's parent. Let's break down nested form possible use-cases in the code below:\n\n```ts\nconst nestedForm = createForm({\n  name: string(),\n  age: number(),\n});\n\nconst form = createForm({\n  // Notice, how nested form is used here, as a part of the main one\n  bio: nestedForm,\n  status: string(),\n});\n\nform.values.watch(console.log);\n// =\u003e {bio: {name: \"\", age: 0}, status: \"\"}\n\nnestedForm.fill({ name: \"John\", age: 42 });\n// =\u003e {bio: {name: \"John\", age: 42}, status: \"\"}\n```\n\nAs you can see, any nested form lifting up it's state, errors, and other things like that. So you are free to separate complicated forms into simplier ones, and then, just combine them at the upper structure level, resulting in solid data structure.\n\nThe next thing on the list - is **Inline-Forms** which are appear to be nested by design. There is an example of such form in the code below:\n\n```ts\nconst form = createForm({\n\tbio: { // this field is actually an inline-form, and it is nested aswell\n\t\tname: string(),\n\t\tage: number()\n\t},\n\tstatus: string()\n});\n\nform.values.watch(console.log);\n\t// =\u003e {bio: {name: \"\", age: 0}, status: \"\"}\n\nform.fill({\n\tbio: {\n\t\tname: \"Alice\",\n\t\tage: 28\n\t}\n})\n\t// =\u003e {bio: {name: \"Alice\", age: 28}, status: \"\"}\n```\n\n### Fields\nIn short, **Field** refers to a part of the form.  \n```ts\ntype Field\u003cT\u003e = {\n  set: Event\u003cT\u003e;\n  value: Store\u003cT\u003e;\n  error: Store\u003cstring | undefined\u003e;\n  validate: Effect\u003cvoid, Errors\u003cT\u003e, Error\u003e;\n};\n```\n\nIt may be either simple field (e.g. string field, numeric field, etc) or even, reference to nested form. Let's look at the example below:\n\n```ts\nconst nestedForm = createForm({\n  name: string(),\n  age: number(),\n});\n\nconst form = createForm({\n  bio: nestedForm, // we have a nested form here\n  location: { // and we also do an inline one\n\t  country: string(),\n\t  city: string()\n  }\n  status: string(),\n});\n\n// Then, we have an access to form's fields\nconsole.log(form.fields.bio.value.getState()) // =\u003e {name: \"\", age: 0}\n\nform.fields.location.set({\n\tcountry: \"France\",\n\tcity: \"Paris\"\n})\n\nconsole.log(form.values.getState()) // =\u003e {status: \"\", location: {country: \"France\", city: \"Paris\"}, bio: {name: \"\", age: 0}}\n```\n\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FtehSLy%2Fefform","html_url":"https://awesome.ecosyste.ms/projects/github.com%2FtehSLy%2Fefform","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FtehSLy%2Fefform/lists"}