{"id":19738288,"url":"https://github.com/httptoolkit/mobx-shallow-undo","last_synced_at":"2025-06-27T01:32:16.640Z","repository":{"id":57156566,"uuid":"313319275","full_name":"httptoolkit/mobx-shallow-undo","owner":"httptoolkit","description":"Zero-config undo \u0026 redo for Mobx","archived":false,"fork":false,"pushed_at":"2023-06-20T15:05:01.000Z","size":28,"stargazers_count":18,"open_issues_count":0,"forks_count":2,"subscribers_count":3,"default_branch":"main","last_synced_at":"2025-06-04T17:11:19.723Z","etag":null,"topics":["mobx","mobx-react","undo","undo-redo"],"latest_commit_sha":null,"homepage":"","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/httptoolkit.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,"governance":null,"roadmap":null,"authors":null}},"created_at":"2020-11-16T13:57:21.000Z","updated_at":"2024-05-11T11:42:00.000Z","dependencies_parsed_at":"2024-01-15T03:41:22.343Z","dependency_job_id":null,"html_url":"https://github.com/httptoolkit/mobx-shallow-undo","commit_stats":null,"previous_names":[],"tags_count":2,"template":false,"template_full_name":null,"purl":"pkg:github/httptoolkit/mobx-shallow-undo","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/httptoolkit%2Fmobx-shallow-undo","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/httptoolkit%2Fmobx-shallow-undo/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/httptoolkit%2Fmobx-shallow-undo/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/httptoolkit%2Fmobx-shallow-undo/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/httptoolkit","download_url":"https://codeload.github.com/httptoolkit/mobx-shallow-undo/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/httptoolkit%2Fmobx-shallow-undo/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":262172438,"owners_count":23270009,"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":["mobx","mobx-react","undo","undo-redo"],"created_at":"2024-11-12T01:13:48.204Z","updated_at":"2025-06-27T01:32:16.611Z","avatar_url":"https://github.com/httptoolkit.png","language":"TypeScript","readme":"# Mobx Shallow Undo [![Build Status](https://github.com/httptoolkit/mobx-shallow-undo/workflows/CI/badge.svg)](https://github.com/httptoolkit/mobx-shallow-undo/actions) [![Available on NPM](https://img.shields.io/npm/v/mobx-shallow-undo.svg)](https://npmjs.com/package/mobx-shallow-undo)\n\n\u003e _Part of [HTTP Toolkit](https://httptoolkit.tech): powerful tools for building, testing \u0026 debugging HTTP(S)_\n\n**Drop-in undo \u0026amp; redo for shallow changes in Mobx**\n\nMobx-shallow-undo is a tiny zero-dependency library for shallow undo/redo on any mobx observable value.\n\nIf you have some changing but internally immutable state anywhere in your app - from core state in your app-wide store down to individual observable fields on your React components - this lets you immediately add undo/redo to that state, and freely flip back and forth through its whole history, with zero hassle or configuration required.\n\nFor example, [HTTP Toolkit](https://httptoolkit.tech/javascript/) uses this to support undo/redo in an autocompleting tagged input field, where undo behaviour needs to manage some of the state in the component, not just the text in the input field itself.\n\nThis is designed for _simple_ cases, where a single observable value (or a single property of an observable object) is changing between different immutable values. By default, this does not handle mutations inside the value or track undo states recursively, it just tracks the shallow undo/redo state of an observable. To track nested properties you can use [.toJS()](https://mobx.js.org/api.html#tojs) as a workaround.\n\nTL;DR: **Mobx-shallow-undo lets you do this:**\n\n```javascript\nimport * as mobx from 'mobx';\nimport { trackUndo } from 'mobx-shallow-undo';\n\nconst myObservable = mobx.observable({ a: 1 });\n\nconst myUndoer = trackUndo(\n    // Getter, this will be observed:\n    () =\u003e myObservable.a,\n    // Setter, to reset the value on undo/redo:\n    (value) =\u003e { myObservable.a = value }\n);\n\nmyObservable.a = 2;\nmyObservable.a = 3;\nmyObservable.a = 1000;\n\nmyUndoer.undo();\nmyUndoer.undo();\n\n// myObservable = { a: 2 };\n\nmyUndoer.redo();\n// myObservable = { a: 3 };\n```\n\nHandle nested data structures like this:\n\n```javascript\nimport React from \"react\";\nimport { render } from \"react-dom\";\nimport * as mobx from \"mobx\";\nimport { trackUndo } from \"mobx-shallow-undo\";\n\nconst myObservable = mobx.observable.array([{ id: 1 }, { id: 2 }]);\n\nconst myUndoer = trackUndo(\n  // .toJS() was added to observe a nested structure\n  () =\u003e mobx.toJS(myObservable),\n  (value) =\u003e {\n    myObservable.replace(value);\n  }\n);\n\nmyObservable.push({ id: 3 });\n\n// myObservable = [{ id: 1 }, { id: 2 }, { id: 3 }];\n\nmyUndoer.undo();\n\n// myObservable = [{ id: 1 }, { id: 2 }];\n```\n\nUsing `observable.array` and its `replace` method is not required. The example above will continue to work with the modern [makeAutoObservable](https://mobx.js.org/observable-state.html#makeautoobservable) Mobx API.\n\n## Getting Started\n\n```bash\nnpm install mobx-shallow-undo\n```\n\n```javascript\nimport { trackUndo } from 'mobx-shallow-undo';\n\nconst undoer = trackUndo(\n    () =\u003e /* Read the undoable observable */,\n    (value) =\u003e { /* Update the undoable observable */ }\n);\n\nundoer.undo(); // Undo the last change, if possible\nundoer.redo(); // Redo the last undo, if possible\n```\n\n## API\n\n### `trackUndo(getter, setter)`\n\nCreates an undoer. `getter` and `setter` must be synchronous functions to get and set an observable value.\n\nThe getter takes no arguments, whilst the setter takes one argument: the new value.\n\nThis returns an `undoer`.\n\n### `undoer.undo()`\n\nUndoes the latest change. If the undo stack is empty this does nothing.\n\n### `undoer.redo()`\n\nRedoes the latest undo. If we're already on the latest change this does nothing.\n\nChanges to the observed value after an undo clear the redo stack, just like undo in every other application.\n\n### `undoer.dispose()`\n\nStops observing the observable and throws away all historical data.\n\nAny future calls to `undo()` or `redo()` will throw an error.\n","funding_links":[],"categories":["Awesome MobX"],"sub_categories":["Related projects and utilities"],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fhttptoolkit%2Fmobx-shallow-undo","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fhttptoolkit%2Fmobx-shallow-undo","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fhttptoolkit%2Fmobx-shallow-undo/lists"}