This repository has been archived by the owner on Nov 23, 2020. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[new package] @reffect/undoable (#7)
* feat: initial commit for reffect-undoable package, add simplest implementation undo redo * feat: create simple undo redo store extension package * chore: change build config (output plugins) * chore: remove build files * chore: add gitignore for reffect/undoable * chore: lock file update * feat: rewrite undoable to reffect store with couple effects (undo, redo) * chore: up size limits for reffect undoable package; chore: change keywords for undoable * docs: update readme for monorepo (add Install section); docs: add readme for undoable package
- Loading branch information
Showing
7 changed files
with
283 additions
and
15 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
reffect-undoable.*.js | ||
reffect-undoable.d.ts | ||
reffect-undoable.*.js.map | ||
package-lock.json |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
[ | ||
{ | ||
"path": "reffect-undoable.es.js", | ||
"webpack": false, | ||
"limit": "410 B" | ||
}, | ||
{ | ||
"path": "reffect-undoable.cjs.js", | ||
"webpack": false, | ||
"limit": "450 B" | ||
}, | ||
{ | ||
"path": "reffect-undoable.umd.js", | ||
"webpack": false, | ||
"limit": "550 B" | ||
} | ||
] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,106 @@ | ||
<div align="center"> | ||
|
||
[![reffect logo](https://raw.githubusercontent.com/acacode/reffect/master/assets/reffect.png)](https://github.com/acacode/reffect) | ||
[![npm](https://img.shields.io/npm/v/@reffect/react?style=flat-square&color=blue)](https://www.npmjs.com/package/@reffect/react) | ||
[![npm bundle size](https://img.shields.io/bundlephobia/minzip/@reffect/react?style=flat-square&color=blue)](https://bundlephobia.com/result?p=@reffect/react) | ||
[![license](https://img.shields.io/github/license/acacode/reffect?style=flat-square&color=blue)](https://github.com/acacode/reffect) | ||
|
||
<div align="left"> | ||
|
||
Reffect — is a declarative and reactive multi-store state manager for JavaScript/TypeScript applications inspired by [Reatom](https://github.com/artalar/reatom) and [Effector](https://github.com/zerobias/effector) | ||
|
||
# @reffect/undoable | ||
|
||
Extension for [`Reffect`](https://github.com/acacode/reffect) stores. | ||
Provides undo/redo effects and store history. | ||
|
||
## How to use | ||
|
||
Import `undoable` function from package: | ||
|
||
```ts | ||
import { undoable } from "@reffect/undoable"; | ||
``` | ||
|
||
Call `undoable` and send to it your store at first argument: | ||
|
||
```ts | ||
import { store } from "@reffect/core"; | ||
const storeRef = store({ foo: "bar" }); | ||
const { history, undo, redo } = undoable(storeRef, middlewares, limit); | ||
// `middlewares` it is array of reffect store middlewares | ||
// `limit` means limit for state history | ||
``` | ||
|
||
### undo (`VoidFunction`) | ||
|
||
This function move state of wrapped store to the previous value | ||
|
||
```ts | ||
undo(); | ||
``` | ||
|
||
### redo (`VoidFunction`) | ||
|
||
This function move state of wrapped store to the next value (if `undo()` was called early) | ||
|
||
```ts | ||
redo(); | ||
``` | ||
|
||
### history (`{ past: Store[]; present: Store; future: Store[]; }`) | ||
|
||
It's reffect store which have state history of wrapped store | ||
|
||
```ts | ||
import { manage } from "@reffect/core"; | ||
|
||
manage(history).subscribe((payload, prevState, currState) => console.log(payload, prevState, currState)); | ||
``` | ||
|
||
## Examples | ||
|
||
```ts | ||
import { store, effect } from "@reffect/core"; | ||
import { undoable } from "@reffect/undoable"; | ||
|
||
const keyboards = store({ list: [] }); | ||
const { history, undo, redo } = undoable(keyboards); | ||
|
||
const addKeyboard = effect(keyboards, name => ({ list: [...keyboards.list, name] })); | ||
|
||
addKeyboard("Das Keyboard 4Q"); | ||
addKeyboard("Leopold FC900R"); | ||
addKeyboard("Leopold FC750R"); | ||
|
||
console.log(keyboards.list); // ["Das Keyboard 4Q", "Leopold FC900R", "Leopold FC750R"] | ||
undo(); | ||
console.log(keyboards.list); // ["Das Keyboard 4Q", "Leopold FC900R"] | ||
undo(); | ||
console.log(keyboards.list); // ["Das Keyboard 4Q"] | ||
redo(); | ||
console.log(keyboards.list); // ["Das Keyboard 4Q", "Leopold FC900R"] | ||
redo(); | ||
console.log(keyboards.list); // ["Das Keyboard 4Q", "Leopold FC900R", "Leopold FC750R"] | ||
|
||
console.log(history); | ||
/* | ||
{ | ||
past: [ | ||
{ | ||
list: [], | ||
}, | ||
{ | ||
list: ["Das Keyboard 4Q"], | ||
}, | ||
{ | ||
list: ["Das Keyboard 4Q", "Leopold FC900R"], | ||
}, | ||
], | ||
present: { | ||
list: ["Das Keyboard 4Q", "Leopold FC900R", "Leopold FC750R"] | ||
}, | ||
future: [] | ||
} | ||
*/ | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,50 @@ | ||
{ | ||
"name": "@reffect/undoable", | ||
"version": "0.0.1", | ||
"description": "Reffect stores extension", | ||
"scripts": { | ||
"build": "node ../../build/build.js", | ||
"size": "size-limit" | ||
}, | ||
"author": "acacode", | ||
"license": "MIT", | ||
"readme": "README.md", | ||
"private": false, | ||
"sideEffects": false, | ||
"main": "reffect-undoable.cjs.js", | ||
"typings": "reffect-undoable.d.ts", | ||
"umd:main": "reffect-undoable.umd.js", | ||
"jsnext:main": "reffect-undoable.es.js", | ||
"module": "reffect-undoable.es.js", | ||
"peerDependencies": { "@reffect/core": "^1.5.0" }, | ||
"devDependencies": { | ||
"@reffect/core": "^1.5.0", | ||
"@size-limit/preset-small-lib": "^4.2.1", | ||
"size-limit": "^4.2.1" | ||
}, | ||
"files": [ | ||
"LICENSE", | ||
"reffect-undoable.d.ts", | ||
"reffect-undoable.cjs.js", | ||
"reffect-undoable.cjs.js.map", | ||
"reffect-undoable.es.js", | ||
"reffect-undoable.es.js.map", | ||
"reffect-undoable.umd.js", | ||
"reffect-undoable.umd.js.map" | ||
], | ||
"keywords": [ | ||
"redux", | ||
"effector", | ||
"mobx", | ||
"state", | ||
"store", | ||
"flux", | ||
"reactive", | ||
"state-manager", | ||
"state manager", | ||
"undo", | ||
"undoable", | ||
"reffect" | ||
], | ||
"gitHead": "7636d0e5d6b6ba2f17c0b415f0761b559ae2a20c" | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,68 @@ | ||
import { StoreType, manage, store, effect, StoreMiddleware } from "@reffect/core"; | ||
|
||
type Undoable<Store extends StoreType> = { | ||
history: StoreHistory<Store>; | ||
undo: VoidFunction; | ||
redo: VoidFunction; | ||
}; | ||
|
||
export type StoreHistory<Store extends StoreType> = { | ||
past: Store[]; | ||
present: Store; | ||
future: Store[]; | ||
}; | ||
|
||
export const undoable = <Store extends StoreType>( | ||
storeRef: Store, | ||
middlewares?: StoreMiddleware<StoreHistory<Store>>[], | ||
limit = 15, | ||
): Undoable<Store> => { | ||
let updateFromUndoable = false; | ||
const storeRefManager = manage(storeRef); | ||
const storeHistory = store<StoreHistory<Store>>( | ||
{ | ||
past: [], | ||
present: storeRefManager.initialState as Store, | ||
future: [], | ||
}, | ||
`${storeRefManager.name}-history`, | ||
middlewares, | ||
); | ||
|
||
const undoRedo = (isRedo?: boolean): Partial<StoreHistory<Store>> | void => { | ||
const historyArray = storeHistory[isRedo ? "future" : "past"]; | ||
if (historyArray.length) { | ||
const sliced = historyArray.slice(); | ||
const present = sliced[isRedo ? "shift" : "pop"](); | ||
if (present) { | ||
updateFromUndoable = true; | ||
storeRefManager.partialUpdate(present); | ||
return { | ||
present, | ||
future: isRedo ? sliced : [storeHistory.present, ...storeHistory.future], | ||
past: isRedo ? [...storeHistory.past, storeHistory.present] : sliced, | ||
}; | ||
} | ||
} | ||
}; | ||
|
||
storeRefManager.subscribe((partialUpdate, prevState, currState) => { | ||
if (updateFromUndoable) { | ||
updateFromUndoable = false; | ||
} else { | ||
const pastLength = storeHistory.past.length; | ||
|
||
manage(storeHistory).partialUpdate({ | ||
present: currState, | ||
future: storeHistory.future.length ? [] : storeHistory.future, | ||
past: [...storeHistory.past.slice(+(pastLength >= limit), pastLength), prevState], | ||
}); | ||
} | ||
}); | ||
|
||
return { | ||
undo: effect(storeHistory, () => undoRedo()), | ||
redo: effect(storeHistory, () => undoRedo(true)), | ||
history: storeHistory, | ||
}; | ||
}; |