{"id":26963962,"url":"https://github.com/intercaetera/fractal-form","last_synced_at":"2025-04-03T06:18:58.839Z","repository":{"id":124225480,"uuid":"596740472","full_name":"intercaetera/fractal-form","owner":"intercaetera","description":"An experimental React form library using lenses.","archived":false,"fork":false,"pushed_at":"2023-02-02T21:02:38.000Z","size":342,"stargazers_count":12,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"master","last_synced_at":"2024-08-08T18:04:27.457Z","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":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/intercaetera.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":"2023-02-02T20:44:38.000Z","updated_at":"2023-04-05T08:20:29.000Z","dependencies_parsed_at":"2023-05-31T01:45:58.272Z","dependency_job_id":null,"html_url":"https://github.com/intercaetera/fractal-form","commit_stats":{"total_commits":5,"total_committers":1,"mean_commits":5.0,"dds":0.0,"last_synced_commit":"dbb25595b19653e79d05b0b13490b670931a91d9"},"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/intercaetera%2Ffractal-form","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/intercaetera%2Ffractal-form/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/intercaetera%2Ffractal-form/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/intercaetera%2Ffractal-form/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/intercaetera","download_url":"https://codeload.github.com/intercaetera/fractal-form/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":246944386,"owners_count":20858772,"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":"2025-04-03T06:18:58.053Z","updated_at":"2025-04-03T06:18:58.801Z","avatar_url":"https://github.com/intercaetera.png","language":"JavaScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# fractal-form\n\nAn experimental React form library using lenses. Lenses are a concept from functional programming. They are modular data accessors that play nice with immutable data. A big advantage of lens implementation in this library is that they are self-similar, so you can create reusable form components at any level of nesting in your application state.\n\nThis library is heavily inspired by André Staltz's [use-profunctor-state](https://github.com/staltz/use-profunctor-state).\n\nSee `src/Example.js` for an example implementation.\n\n## Installation\n\n```\nnpm install fractal-form\n```\n\n## Usage\n\n### Basic example\n\n```jsx\nimport { memo, useState } from \"react\"\nimport { useFractalForm, useLensField } from \"fractal-form\"\n\nconst Input = memo(({ label, value, onChange }) =\u003e (\n  \u003clabel\u003e{label}:\n    \u003cinput value={value} onChange={onChange} /\u003e\n  \u003c/label\u003e\n))\n\nexport const Basic = () =\u003e {\n  const [submittedValues, setSubmittedValues] = useState({})\n  const {useFormLens, value} = useFractalForm({ name: '' })\n  const [nameField] = useLensField(useFormLens, 'name')\n\n  const submitForm = () =\u003e setSubmittedValues(value)\n  \n  return (\n    \u003cdiv\u003e\n      \u003cInput label=\"Name\" {...nameField} /\u003e\n      \u003cbutton onClick={submitForm}\u003eSubmit form\u003c/button\u003e\n      \u003cpre\u003e{JSON.stringify(submittedValues, null, 2)}\u003c/pre\u003e\n    \u003c/div\u003e\n  )\n}\n```\n\n## API Reference\n\n#### `useFractalForm`\n\n```javascript\nconst initialValues = { name: 'Bob' }\nconst {\n  form, value, error, touched,\n  setForm, setValues, setErrors, setTouched,\n  useFormLens, useValuesLens, useErrorsLens, useTouchedLens,\n} = useFractalForm(initialValues)\n```\n\nCreate a form object for a given initial state.\n\n- `form` is the entire form state, an object composed of keys `{ value, error, touched }`.\n- `value` contains the form values. Initially set to `initialValues`.\n- `error` contains the errors. Initially set to `{}`\n- `touched` contains the touched status of the fields. Initally set to `{}`\n\n- `set*` are functions that set the given object outright. You probably should avoid using those.\n\n- `use*Lens` are hooks which provide lenses to each one of the properties. They are the same as `useLens` hooks returned from `useLensState` (see below).\n\n\n#### `useLensField`\n```javascript\nconst validateName = (_parentValue, name) =\u003e name.length \u003c 5 ? \"Name too short\" : null\n\nconst { useFormLens } = useFractalForm({ name: 'Bob' })\n\nconst [nameField, setNameField, useNameFieldLens] = useLensField(useFormLens, 'name', validateName)\n\nreturn (\n  \u003cinput {...nameField} /\u003e\n)\n```\n\nThis hook creates a lens that focuses on a particular field name from the `value`, `touched`, and `error` object.\n\n- `nameField` is a utility object containing the `value`, `error`, and `touched` values for the given field name as well as `onChange` (updates the value and validates it) and `onBlur` (sets `touched` to true) callbacks.\n- `setNameField` expects an object of `{ value, error, touched }` for the given field\n- `useNameFieldLens` is a lens for the value, error and touched for the given field. It can be provided as the first argument to another `useLensField`\n\n#### `useLensState`\n\n```javascript\n  const [state, setState, useLens] = useLensState({ name: 'Bob' })\n  const [name, setName] = useLens(s =\u003e s.name, (s, a) =\u003e ({ ...s, name: a }))\n\n  console.log(state) // -\u003e { name: 'Bob' }\n  console.log(name) // -\u003e 'Bob'\n\n  setName('Alice')\n\n  console.log(name) // -\u003e 'Alice'\n  console.log(state) // -\u003e { name: 'Alice' }\n\n  setState({ name: 'Charles' })\n\n  console.log(name) // -\u003e 'Charles'\n```\n\nThis hook is exactly the same as React's `useState` except it adds another element to the array. `useLens` is a hook that takes two functions:\n\n- `view: s =\u003e a` takes a full state `s` and returns a partial state `a`\n- `update: (s, a) =\u003e t` takes a full state `s` and a new partial state `a` and returns a new full state `t`\n\nThe two states are going to be synchronised.\n\nThe lenses are memoized so most of the time wrapping a component which uses them in `React.memo` should prevent unnecessary rerenders.\n\n#### `lensForProp`\n\n```javascript\nconst [state, setState, useLens] = useLensState({ name: 'Bob' })\nconst [name, setName] = useLens(...lensForProp('name'))\n```\n\nA helper which takes a key name returns a pair of functions `[view, update]` for that key name.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fintercaetera%2Ffractal-form","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fintercaetera%2Ffractal-form","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fintercaetera%2Ffractal-form/lists"}