Ecosyste.ms: Awesome
An open API service indexing awesome lists of open source software.
https://github.com/widdershin/rx-undoable
Easily add undo and redo to your RxJS or Cycle.js apps
https://github.com/widdershin/rx-undoable
Last synced: 21 days ago
JSON representation
Easily add undo and redo to your RxJS or Cycle.js apps
- Host: GitHub
- URL: https://github.com/widdershin/rx-undoable
- Owner: Widdershin
- License: mit
- Created: 2015-10-19T19:08:23.000Z (about 9 years ago)
- Default Branch: master
- Last Pushed: 2016-10-25T21:53:56.000Z (about 8 years ago)
- Last Synced: 2024-10-04T13:14:32.241Z (about 1 month ago)
- Language: JavaScript
- Homepage:
- Size: 270 KB
- Stars: 22
- Watchers: 4
- Forks: 0
- Open Issues: 4
-
Metadata Files:
- Readme: README.md
- License: LICENSE
Awesome Lists containing this project
README
[![npm version](https://badge.fury.io/js/rx-undoable.svg)](http://badge.fury.io/js/rx-undoable)
[![Build Status](https://travis-ci.org/Widdershin/rx-undoable.svg?branch=master)](https://travis-ci.org/Widdershin/rx-undoable)* * *
# rx-undoable
Easily undo and redo RxJS observables.
Great for adding undo and redo buttons to Cycle.js applications.
Installation
---`npm install --save rx-undoable`
Usage
---```js
import undoableScan from 'rx-undoable';const numbers$ = Rx.Observable.range(1, 5);
const undo$ = Rx.Observable.just(1).delay(1000); // observable of undo intent, like clicking an undo button
const undoableSum$ = undoableScan(
numbers$,
(total, change) => total + change,
0,
undo$
).pluck('present');
```API
---###`undoableScan(stream$, f, initialValue, undo$, [redo$, {historySize: Infinite}])`
Which is equivalent to `stream$.scan(f, initialValue)`, except that data is returned in this format:
```js
{
past: [...],
present: thing,
future: [...]
}
```So to get the present data, use `undoableScan(...).pluck('present')`.
Arguments:
`stream$`: An RxJS stream
`f`: A function as you would use with `scan` or `reduce`. `(previousValue, currentValue) => nextValue`
`initialValue`: The initial value to be used as `present`.
`undo$`: An RxJS stream that will cause an undo each time it emits
`redo$`: An optional RxJS stream that will cause a redo each time it emits`options`: An optional object carrying additional options
`historySize`: A size limit for the `past` array. Defaults to InfinityExample
---Let's take a simple counter example from the Cycle.js docs and add undo and redo buttons.
Before:
```js
import Rx from 'rx';
import {run} from '@cycle/core';
import {h, makeDOMDriver} from '@cycle/dom';function main ({DOM}) {
let action$ = Rx.Observable.merge(
DOM.select('.subtract').events('click').map(ev => -1),
DOM.select('.add').events('click').map(ev => +1)
);let count$ = action$
.startWith(0)
.scan((x, y) => x + y);return {
DOM: count$.map(count =>
h('div', [
h('button.subtract', 'Subtract'),
h('button.add', 'Add'),h('p', 'Counter: ' + count)
])
)
};
}run(main, {
DOM: makeDOMDriver('.app')
});
```After:
```js
import Rx from 'rx';
import {run} from '@cycle/core';
import {h, makeDOMDriver} from '@cycle/dom';
import undoableScan from 'rx-undoable';function main ({DOM}) {
let action$ = Rx.Observable.merge(
DOM.select('.subtract').events('click').map(ev => -1),
DOM.select('.add').events('click').map(ev => +1)
);let undo$ = DOM.select('.undo').events('click'); // NEW
let redo$ = DOM.select('.redo').events('click'); // NEWlet count$ = undoableScan( // NEW
action$, // NEW
(x, y) => x + y, // NEW
0, // NEW
undo$, // NEW
redo$ // NEW
).pluck('present'); // NEWreturn {
DOM: count$.map(count =>
h('div', [
h('button.undo', 'Undo'), // NEW
h('button.redo', 'Redo'), // NEWh('button.subtract', 'Subtract'),
h('button.add', 'Add'),h('p', 'Counter: ' + count)
])
)
};
}run(main, {
DOM: makeDOMDriver('.app')
});
```Prior art
---`rx-undoable` was inspired by [omnidan/redux-undo](https://github.com/omnidan/redux-undo) and the algorithm used is described very eloquently by [Dan Abramov in the Redux documentation](http://redux.js.org/docs/recipes/ImplementingUndoHistory.html).
Contributing
---Issues, pull requests and feedback of all sorts welcome! If you're unsure, send me an email at [[email protected]](mailto:[email protected]).