{"id":13793552,"url":"https://github.com/elisherer/hyperapp-forms","last_synced_at":"2025-04-12T12:05:49.768Z","repository":{"id":57270109,"uuid":"138562493","full_name":"elisherer/hyperapp-forms","owner":"elisherer","description":"3KB Hyperapp form state management library","archived":false,"fork":false,"pushed_at":"2018-07-21T20:50:44.000Z","size":24,"stargazers_count":9,"open_issues_count":1,"forks_count":1,"subscribers_count":2,"default_branch":"master","last_synced_at":"2025-03-26T06:43:30.831Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"JavaScript","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/elisherer.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2018-06-25T08:02:47.000Z","updated_at":"2020-07-17T01:52:39.000Z","dependencies_parsed_at":"2022-09-02T05:22:05.635Z","dependency_job_id":null,"html_url":"https://github.com/elisherer/hyperapp-forms","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/elisherer%2Fhyperapp-forms","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/elisherer%2Fhyperapp-forms/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/elisherer%2Fhyperapp-forms/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/elisherer%2Fhyperapp-forms/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/elisherer","download_url":"https://codeload.github.com/elisherer/hyperapp-forms/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248565068,"owners_count":21125415,"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":[],"created_at":"2024-08-03T23:00:24.100Z","updated_at":"2025-04-12T12:05:49.737Z","avatar_url":"https://github.com/elisherer.png","language":"JavaScript","funding_links":[],"categories":["Utilities V1"],"sub_categories":[],"readme":"[![npm version](https://badge.fury.io/js/hyperapp-forms.svg)](https://badge.fury.io/js/hyperapp-forms)\n\n\n# hyperapp-forms\n\nHyperapp form state management library\n\n* Simple\n* Small in size (3kb minified)\n\n**Heavily inspired by [`redux-form`](https://redux-form.com/)**\n\n## Installation\n\n```\nnpm i -S hyperapp-forms\n```\n\n## Usage\n\n\n### Import \n\nAdd the imported actions object contents to the main actions object.\n\n```js\n\nimport forms from 'hyperapp-forms';\n\n..\n\nconst actions = {\n  ..\n\n  ...forms,\n};\n\n..\n\napp(state,actions,view,document.body);\n\n```\n\n### Field components\n\nWrap your input components with the `Field` decorator.\n\nTextbox.js\n```js\nimport { h } from 'hyperapp';\nimport {Field} from \"hyperapp-forms\";\n\nconst Textbox = ({ input, type, name, title, disabled }) =\u003e {\n  const showError = (input.touched || input.submitted) \u0026\u0026 !!input.error;\n  return (\n    \u003clabel\u003e\n      {title}\n      \u003cinput type={type}\n             name={name}\n             value={input.value}\n             disabled={disabled}\n             onchange={input.onchange}\n             onfocus={input.onfocus}\n      /\u003e\n      {showError \u0026\u0026 \u003csup\u003e{input.error}\u003c/sup\u003e}\n    \u003c/label\u003e\n  );\n};\n\nexport default Field(Textbox);\n```\n\nThe attributes the `Field` decorator adds to the component are:\n\n|Attribute|Type|Description|\n|---|---|---|\n|form|string|The form's name|\n|name|string|The field's name|\n|validate|function(form, name, values) : Object |A validate function to run after change\n\n## Actions\n\n### `changeAndValidate({ form, name, value, validate })`\n\nChanges a value for a certain field, also runs the `validate` function and updates the sync errors accordingly.\n\n`validate` is a callback with the following structure `validate(form, name, values)` (see explanation above).\n\n### `touch({ form, name })`\n\nSets the field as been touched.\n\n### `startSubmit({ form })`\n\nSets the form's status to be submitting\n\n### `stopSubmit({ form, errors })`\n\nSets the form's status to be not submitting, and apply server errors by matching field names.\n\n\n## Selectors\n\n|Selector|Description|\n|---|---|\n|`getFormValues(state, form)`|Get an object with the form values|\n|`isSubmitting(state, form)`|Is the form submitting|\n|`isValid(state, form)`|Is the form valid (are there any errors)|\n|`wasSubmitted(state, form)`|Was the form submitted at least once (useful for showing errors)|\n|`getFieldValue(state, form, field)`|Get a certain field value|\n|`getFieldError(state, form, field)`|Get a certain field error|\n|`isFieldTouched(state, form, field)`|Was field touched (useful for showing errors)|\n\n## Submission and error handling\n\n`handleSubmit(state, actions, form, callback)`\n\nUse `handleSubmit` in the form's onsubmit (or any button's callback, see example below),\n\nSupply a callback function which will return a promise, which at first will start the form's submission automatically.\n\nAnd once resolved or rejected will stop the form's submission.\n\nThe callback function needs to be in the following structure:\n\n`callback(values, actions) : Promise`\n\nThe resolve or reject argument should be\n\n\n## Usage example\n\nCheckout a working example: [hyperapp-less-boilerplate](https://github.com/elisherer/hyperapp-less-boilerplate)\n\n```js\n\nconst signIn = (values, actions) =\u003e new Promise((resolve, reject) =\u003e {\n  setTimeout(() =\u003e {\n    if (values.username === 'test') {\n      actions.login.login();\n      resolve();\n    }\n    else {\n      reject({ username: 'Not \"test\"!'});\n    }\n  }, 2000);\n});\n\nconst validate = (form, name, values) =\u003e {\n\n  let errors = null;\n\n  const usernameInvalid = !/^t/.test(values.username);\n  if (usernameInvalid) {\n    if (!errors) errors = {};\n    errors.username = 'not starting with t!';\n  }\n\n  const passwordInvalid = !values.password;\n  if (passwordInvalid) {\n    if (!errors) errors = {};\n    errors.password = 'password is required!';\n  }\n\n  return errors; // if everything is valid, returns null\n};\n\n\nexport default (state, actions) =\u003e {\n\n  const submitting = isSubmitting(state, 'login');\n\n  return (\n    \u003cform onsubmit={handleSubmit(state, actions, 'login', signIn)}\u003e\n\n      \u003ch2\u003eLogin to your account:\u003c/h2\u003e\n\n      \u003cTextbox type=\"text\" form=\"login\" name=\"username\" title=\"Username\" disabled={submitting} validate={validate}/\u003e\n      \u003cTextbox type=\"password\" form=\"login\" name=\"password\" title=\"Password\" disabled={submitting} validate={validate}/\u003e\n\n      \u003cCheckbox form=\"login\" name=\"rememberMe\" title=\"Remember me\" disabled={submitting}/\u003e\n\n      \u003cbutton disabled={submitting}\u003eSign In\u003c/button\u003e\n\n      {submitting \u0026\u0026 \u003cdiv data-loader /\u003e}\n\n    \u003c/form\u003e\n  );\n});\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Felisherer%2Fhyperapp-forms","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Felisherer%2Fhyperapp-forms","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Felisherer%2Fhyperapp-forms/lists"}