GithubHelp home page GithubHelp logo

undo's Introduction

Undo

A simple undo / redo manager. This was designed to work well with Replicache, but can be used entirely independently. From this library's perspective, undo/redo actions are just functions and this library doesn't care what those functions do. Please use Replidraw as a reference on how to use the library.

Installation

npm install @rocicorp/undo

Replicache Usage Example

import { Replicache } from "replicache";
import { useSubscribe } from "replicache-react";
...
import {UndoManager} from '@rocicorp/undo';

// Replicache and UndoManager are initialized outside of the initial component render.
// undoManager = new UndoManager()
const App = ({ rep }: { rep: Replicache<M>, undoManager: UndoManager }) => {
  const todos = useSubscribe(rep, listTodos, [], [rep]);

 // new item with undo
  const handleNewItem = (text: string) => {
    const id = nanoid();
    //function that will redo and execute
    const putTodo = () => {
      rep.mutate.putTodo({
        id,
        text: text,
        sort: todos.length > 0 ? todos[todos.length - 1].sort + 1 : 0,
        completed: false,
      });
    };

    //undo function
    const removeTodo = () => rep.mutate.deleteTodos([id]);

    undoManager.add({
      execute: putTodo,
      undo: removeTodo,
    });
  };

  return (
    <div>
      <Header onNewItem={handleNewItem} />
      <MainSection
        todos={todos}
      />
    </div>
  );
}

Basic Usage Example

import {UndoManager} from '@rocicorp/undo';

const undoManager = new UndoManager();
const modifiedValue = 0;
undoManager.add({
  undo: () => {
    modifiedValue--;
  },
  execute: () => {
    modifiedValue++;
  },
});

API

constructor

Constructor for UndoManager

Param Type Description
options UnderManagerOptions Options passed for undo manager constructor

UnderManagerOptions

Param Type Description
maxSize Object The maximum number of entries in the stack. Default is 10000.
onChange (undoManager: UndoRedoStackState) => void A callback function to be called when the stack canUndo or canRedo values change.

Example

   const undoManager = new UndoManager({ 10, (e: UndoRedoStackState) => {
    console.log('undo manager canUndo or canRedo values changed -- ', e.canUndo, e.canRedo);
   }});

canUndo

Determines if a user can perform the undo operation on the undoRedo stack.


canRedo

Determines if a user can perform the redo operation on the undoRedo stack.


add

Adds an entry to the undoRedo stack.

Param Type Description
options AddOptions A UndoRedo or ExecuteUndo object that can is added to the stack. If it is an ExecuteUndo it will run the execute function immediately after adding to the stack.

AddOptions

type AddOptions = UndoRedo | ExecuteUndo;

type UndoRedo = {
  redo: () => MaybePromise<void>;
  undo: () => MaybePromise<void>;
};

type ExecuteUndo = {
  execute: () => MaybePromise<void>;
  undo: () => MaybePromise<void>;
};

undo

Executes the undo function of the current entry in the undoRedo stack. If the current entry has groupID it will check the upcoming undo entry. If the upcoming undo entry also has the same groupID the function will recursively call undo until it runs into a entry that has has a different groupID or is undefined.


redo

Executes the redo function of the current entry in the undoRedo stack. If the current entry has groupID it will check the upcoming redo entry. If the upcoming redo entry also has the same groupID the function will recursively call redo until it runs into a entry that has has a different groupID or is undefined.


startGroup

Sets the undo manager to add groupID to all subsequent entries. Sets the isGrouping internal state of the stack to true


endGroup

Sets the undo manager to mark all subsequent added entries groupID to undefined. Sets the isGrouping internal state of the stack to false


undo's People

Contributors

cesara avatar arv avatar

Stargazers

Jesse McLean avatar  avatar  avatar Abbey Hawk Sparrow avatar Mikey avatar nichoth avatar Tom Locke avatar  avatar Mattèo Gauthier avatar Julian Benegas avatar Cacaci avatar Brian Hung avatar Nikolas Evers avatar Marco Roth avatar Joshua Reibert avatar Valentin Laurent avatar Eddy Recio avatar Masanori Ogino avatar Eric Bailey avatar Florian Wendelborn avatar Oskar avatar Andrew Chou avatar Jason Heppler avatar Tom MacWright avatar

Watchers

 avatar Aaron Boodman avatar Phritz avatar  avatar Martin Adams avatar Greg Baker avatar  avatar

undo's Issues

add keypress event handlers

It would be a nice (optional) developer convenience to have a method like addListeners(EventTarget) that adds the relevant keypress events. Something like:

undoManager.addListeners(window);
undoManager.removeListeners(window);

Redoing undo

This particular issue may be what @cesara is mentioning in rocicorp/replicache#1008 (comment), not sure, so reposting here.

const execute = () => rep.mutate.todoCreate({ ...todo })
const undo = () => rep.mutate.todoDelete(todoId)
repUndo.add({ execute, undo })

When attempting to redo the undo, Replicache attempts to create a new task using the same todo.id that was used initially.

Wouldn’t be an issue if it weren’t for the fact that the todoDelete mutation only soft deletes the record, so creating the same record again causes a duplicate record error.

One solution could perhaps be doing something like: repUndo.add({ execute, undo, redo }) with redo() being an optionally different function (and if not specified, it’s the execute() function).

Feedback: save action type to UndoManager

It would be awesome if we could save to the UndoManager what kind of action is to be undone or redone.

Pseudo code:

const [undoPossible, setUndoPossible] = useState(null)
const undoManager = new UndoManager({ onChange: setUndoPossible })
...
if (undoPossible?.canUndo) console.log(`Click here to undo ${undoPossible?.action}.`) // Click here to undo task create.

That way, we can easily indicate in the UX what the user can undo (e.g. via an undo button): “Undo task create”

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.