Comparing version 1.0.7 to 1.1.0
import { createProxy, isChanged } from 'proxy-compare'; | ||
import { subscribe, snapshot, proxy } from 'valtio/vanilla'; | ||
import { subscribe, snapshot, proxy, ref } from 'valtio/vanilla'; | ||
const subscribeKey = (proxyObject, key, callback, notifyInSync) => { | ||
let prevValue = proxyObject[key]; | ||
return subscribe(proxyObject, () => { | ||
const nextValue = proxyObject[key]; | ||
if (!Object.is(prevValue, nextValue)) { | ||
callback(prevValue = nextValue); | ||
} | ||
}, notifyInSync); | ||
}; | ||
const subscribeKey = (proxyObject, key, callback, notifyInSync) => subscribe(proxyObject, (ops) => { | ||
if (ops.some((op) => op[1][0] === key)) { | ||
callback(proxyObject[key]); | ||
} | ||
}, notifyInSync); | ||
const devtools = (proxyObject, name) => { | ||
@@ -180,3 +176,36 @@ let extension; | ||
}; | ||
const proxyWithHistory = (initialValue) => { | ||
const proxyObject = proxy({ | ||
value: initialValue, | ||
history: ref({ | ||
wip: initialValue, | ||
snapshots: [], | ||
index: -1 | ||
}), | ||
canUndo: () => proxyObject.history.index > 0, | ||
undo: () => { | ||
if (proxyObject.canUndo()) { | ||
proxyObject.value = proxyObject.history.wip = proxyObject.history.snapshots[--proxyObject.history.index]; | ||
} | ||
}, | ||
canRedo: () => proxyObject.history.index < proxyObject.history.snapshots.length - 1, | ||
redo: () => { | ||
if (proxyObject.canRedo()) { | ||
proxyObject.value = proxyObject.history.wip = proxyObject.history.snapshots[++proxyObject.history.index]; | ||
} | ||
}, | ||
saveHistory: () => { | ||
proxyObject.history.snapshots.splice(proxyObject.history.index + 1); | ||
proxyObject.history.snapshots.push(snapshot(proxyObject).value); | ||
++proxyObject.history.index; | ||
} | ||
}); | ||
subscribe(proxyObject, (ops) => { | ||
if (ops.some((op) => op[1][0] === "value" && (op[0] !== "set" || op[2] !== proxyObject.history.wip))) { | ||
proxyObject.saveHistory(); | ||
} | ||
}); | ||
return proxyObject; | ||
}; | ||
export { addComputed, devtools, proxyWithComputed, subscribeKey, watch }; | ||
export { addComputed, devtools, proxyWithComputed, proxyWithHistory, subscribeKey, watch }; |
declare const enum AsRef { | ||
} | ||
export declare const ref: <T extends object>(o: T) => T & AsRef; | ||
declare type Path = (string | symbol)[]; | ||
declare type Op = [op: 'set', path: Path, value: unknown, prevValue: unknown] | [op: 'delete', path: Path, prevValue: unknown] | [op: 'resolve', path: Path, value: unknown] | [op: 'reject', path: Path, error: unknown]; | ||
export declare const proxy: <T extends object>(initialObject?: T) => T; | ||
export declare const getVersion: (proxyObject: any) => number; | ||
export declare const subscribe: (proxyObject: any, callback: () => void, notifyInSync?: boolean | undefined) => () => void; | ||
export declare const subscribe: (proxyObject: any, callback: (ops: Op[]) => void, notifyInSync?: boolean | undefined) => () => void; | ||
export declare type DeepResolveType<T> = T extends Function ? T : T extends AsRef ? T : T extends Promise<infer V> ? V : T extends object ? { | ||
@@ -8,0 +10,0 @@ [K in keyof T]: DeepResolveType<T[K]>; |
@@ -27,3 +27,3 @@ import { getUntracked, markToTrack } from 'proxy-compare'; | ||
const listeners = new Set(); | ||
const notifyUpdate = (nextVersion) => { | ||
const notifyUpdate = (op, nextVersion) => { | ||
if (!nextVersion) { | ||
@@ -34,5 +34,23 @@ nextVersion = ++globalVersion; | ||
version = nextVersion; | ||
listeners.forEach((listener) => listener(nextVersion)); | ||
listeners.forEach((listener) => listener(op, nextVersion)); | ||
} | ||
}; | ||
const propListeners = new Map(); | ||
const getPropListener = (prop) => { | ||
let propListener = propListeners.get(prop); | ||
if (!propListener) { | ||
propListener = (op, nextVersion) => { | ||
const newOp = [...op]; | ||
newOp[1] = [prop, ...newOp[1]]; | ||
notifyUpdate(newOp, nextVersion); | ||
}; | ||
propListeners.set(prop, propListener); | ||
} | ||
return propListener; | ||
}; | ||
const popPropListener = (prop) => { | ||
const propListener = propListeners.get(prop); | ||
propListeners.delete(prop); | ||
return propListener; | ||
}; | ||
const createSnapshot = (target, receiver) => { | ||
@@ -91,7 +109,7 @@ const cache = snapshotCache.get(receiver); | ||
if (childListeners) { | ||
childListeners.delete(notifyUpdate); | ||
childListeners.delete(popPropListener(prop)); | ||
} | ||
const deleted = Reflect.deleteProperty(target, prop); | ||
if (deleted) { | ||
notifyUpdate(); | ||
notifyUpdate(["delete", [prop], prevValue]); | ||
} | ||
@@ -108,3 +126,3 @@ return deleted; | ||
if (childListeners) { | ||
childListeners.delete(notifyUpdate); | ||
childListeners.delete(popPropListener(prop)); | ||
} | ||
@@ -116,7 +134,7 @@ if (refSet.has(value) || !isSupportedObject(value) || ((_a = Object.getOwnPropertyDescriptor(target, prop)) == null ? void 0 : _a.set)) { | ||
target[prop][PROMISE_RESULT] = v; | ||
notifyUpdate(); | ||
notifyUpdate(["resolve", [prop], v]); | ||
return v; | ||
}).catch((e) => { | ||
target[prop][PROMISE_ERROR] = e; | ||
notifyUpdate(); | ||
notifyUpdate(["reject", [prop], e]); | ||
}); | ||
@@ -130,5 +148,5 @@ } else { | ||
} | ||
target[prop][LISTENERS].add(notifyUpdate); | ||
target[prop][LISTENERS].add(getPropListener(prop)); | ||
} | ||
notifyUpdate(); | ||
notifyUpdate(["set", [prop], value, prevValue]); | ||
return true; | ||
@@ -159,5 +177,7 @@ } | ||
let pendingVersion = 0; | ||
const listener = (nextVersion) => { | ||
const ops = []; | ||
const listener = (op, nextVersion) => { | ||
ops.push(op); | ||
if (notifyInSync) { | ||
callback(); | ||
callback(ops.splice(0)); | ||
return; | ||
@@ -168,3 +188,3 @@ } | ||
if (nextVersion === pendingVersion) { | ||
callback(); | ||
callback(ops.splice(0)); | ||
} | ||
@@ -171,0 +191,0 @@ }); |
{ | ||
"name": "valtio", | ||
"private": false, | ||
"version": "1.0.7", | ||
"version": "1.1.0", | ||
"description": "💊 Valtio makes proxy-state simple for React and Vanilla", | ||
@@ -6,0 +6,0 @@ "main": "index.js", |
@@ -296,2 +296,17 @@ <img src="logo.svg" alt="valtio"> | ||
#### `proxyWithHistory` util | ||
This is a utility function to create a proxy with snapshot history. | ||
```js | ||
const state = proxyWithHistory({ count: 0 }) | ||
console.log(state.value) // ---> { count: 0 } | ||
state.value.count += 1 | ||
console.log(state.value) // ---> { count: 1 } | ||
state.undo() | ||
console.log(state.value) // ---> { count: 0 } | ||
state.redo() | ||
console.log(state.value) // ---> { count: 1 } | ||
``` | ||
#### Recipes | ||
@@ -298,0 +313,0 @@ |
declare const enum AsRef { | ||
} | ||
export declare const ref: <T extends object>(o: T) => T & AsRef; | ||
declare type Path = (string | symbol)[]; | ||
declare type Op = [ | ||
/*op*/ 'set', | ||
/*path*/ Path, | ||
/*value*/ unknown, | ||
/*prevValue*/ unknown | ||
] | [ | ||
/*op*/ 'delete', | ||
/*path*/ Path, | ||
/*prevValue*/ unknown | ||
] | [ | ||
/*op*/ 'resolve', | ||
/*path*/ Path, | ||
/*value*/ unknown | ||
] | [ | ||
/*op*/ 'reject', | ||
/*path*/ Path, | ||
/*error*/ unknown | ||
]; | ||
export declare const proxy: <T extends object>(initialObject?: T) => T; | ||
export declare const getVersion: (proxyObject: any) => number; | ||
export declare const subscribe: (proxyObject: any, callback: () => void, notifyInSync?: boolean | undefined) => () => void; | ||
export declare const subscribe: (proxyObject: any, callback: (ops: Op[]) => void, notifyInSync?: boolean | undefined) => () => void; | ||
export declare type DeepResolveType<T> = T extends Function ? T : T extends AsRef ? T : T extends Promise<infer V> ? V : T extends object ? { | ||
@@ -8,0 +27,0 @@ [K in keyof T]: DeepResolveType<T[K]>; |
declare const enum AsRef { | ||
} | ||
export declare const ref: <T extends object>(o: T) => T & AsRef; | ||
declare type Path = (string | symbol)[]; | ||
declare type Op = [ | ||
/*op*/ 'set', | ||
/*path*/ Path, | ||
/*value*/ unknown, | ||
/*prevValue*/ unknown | ||
] | [ | ||
/*op*/ 'delete', | ||
/*path*/ Path, | ||
/*prevValue*/ unknown | ||
] | [ | ||
/*op*/ 'resolve', | ||
/*path*/ Path, | ||
/*value*/ unknown | ||
] | [ | ||
/*op*/ 'reject', | ||
/*path*/ Path, | ||
/*error*/ unknown | ||
]; | ||
export declare const proxy: <T extends object>(initialObject?: T) => T; | ||
export declare const getVersion: (proxyObject: any) => number; | ||
export declare const subscribe: (proxyObject: any, callback: () => void, notifyInSync?: boolean | undefined) => () => void; | ||
export declare const subscribe: (proxyObject: any, callback: (ops: Op[]) => void, notifyInSync?: boolean | undefined) => () => void; | ||
export declare type DeepResolveType<T> = T extends Function ? T : T extends AsRef ? T : T extends Promise<infer V> ? V : T extends object ? { | ||
@@ -8,0 +27,0 @@ [K in keyof T]: DeepResolveType<T[K]>; |
51
utils.js
@@ -9,8 +9,7 @@ 'use strict'; | ||
var subscribeKey = function subscribeKey(proxyObject, key, callback, notifyInSync) { | ||
var prevValue = proxyObject[key]; | ||
return vanilla.subscribe(proxyObject, function () { | ||
var nextValue = proxyObject[key]; | ||
if (!Object.is(prevValue, nextValue)) { | ||
callback(prevValue = nextValue); | ||
return vanilla.subscribe(proxyObject, function (ops) { | ||
if (ops.some(function (op) { | ||
return op[1][0] === key; | ||
})) { | ||
callback(proxyObject[key]); | ||
} | ||
@@ -231,2 +230,41 @@ }, notifyInSync); | ||
}; | ||
var proxyWithHistory = function proxyWithHistory(initialValue) { | ||
var proxyObject = vanilla.proxy({ | ||
value: initialValue, | ||
history: vanilla.ref({ | ||
wip: initialValue, | ||
snapshots: [], | ||
index: -1 | ||
}), | ||
canUndo: function canUndo() { | ||
return proxyObject.history.index > 0; | ||
}, | ||
undo: function undo() { | ||
if (proxyObject.canUndo()) { | ||
proxyObject.value = proxyObject.history.wip = proxyObject.history.snapshots[--proxyObject.history.index]; | ||
} | ||
}, | ||
canRedo: function canRedo() { | ||
return proxyObject.history.index < proxyObject.history.snapshots.length - 1; | ||
}, | ||
redo: function redo() { | ||
if (proxyObject.canRedo()) { | ||
proxyObject.value = proxyObject.history.wip = proxyObject.history.snapshots[++proxyObject.history.index]; | ||
} | ||
}, | ||
saveHistory: function saveHistory() { | ||
proxyObject.history.snapshots.splice(proxyObject.history.index + 1); | ||
proxyObject.history.snapshots.push(vanilla.snapshot(proxyObject).value); | ||
++proxyObject.history.index; | ||
} | ||
}); | ||
vanilla.subscribe(proxyObject, function (ops) { | ||
if (ops.some(function (op) { | ||
return op[1][0] === 'value' && (op[0] !== 'set' || op[2] !== proxyObject.history.wip); | ||
})) { | ||
proxyObject.saveHistory(); | ||
} | ||
}); | ||
return proxyObject; | ||
}; | ||
@@ -236,3 +274,4 @@ exports.addComputed = addComputed; | ||
exports.proxyWithComputed = proxyWithComputed; | ||
exports.proxyWithHistory = proxyWithHistory; | ||
exports.subscribeKey = subscribeKey; | ||
exports.watch = watch; |
declare const enum AsRef { | ||
} | ||
export declare const ref: <T extends object>(o: T) => T & AsRef; | ||
declare type Path = (string | symbol)[]; | ||
declare type Op = [op: 'set', path: Path, value: unknown, prevValue: unknown] | [op: 'delete', path: Path, prevValue: unknown] | [op: 'resolve', path: Path, value: unknown] | [op: 'reject', path: Path, error: unknown]; | ||
export declare const proxy: <T extends object>(initialObject?: T) => T; | ||
export declare const getVersion: (proxyObject: any) => number; | ||
export declare const subscribe: (proxyObject: any, callback: () => void, notifyInSync?: boolean | undefined) => () => void; | ||
export declare const subscribe: (proxyObject: any, callback: (ops: Op[]) => void, notifyInSync?: boolean | undefined) => () => void; | ||
export declare type DeepResolveType<T> = T extends Function ? T : T extends AsRef ? T : T extends Promise<infer V> ? V : T extends object ? { | ||
@@ -8,0 +10,0 @@ [K in keyof T]: DeepResolveType<T[K]>; |
@@ -43,3 +43,3 @@ 'use strict'; | ||
var notifyUpdate = function notifyUpdate(nextVersion) { | ||
var notifyUpdate = function notifyUpdate(op, nextVersion) { | ||
if (!nextVersion) { | ||
@@ -52,3 +52,3 @@ nextVersion = ++globalVersion; | ||
listeners.forEach(function (listener) { | ||
return listener(nextVersion); | ||
return listener(op, nextVersion); | ||
}); | ||
@@ -58,2 +58,26 @@ } | ||
var propListeners = new Map(); | ||
var getPropListener = function getPropListener(prop) { | ||
var propListener = propListeners.get(prop); | ||
if (!propListener) { | ||
propListener = function propListener(op, nextVersion) { | ||
var newOp = [].concat(op); | ||
newOp[1] = [prop].concat(newOp[1]); | ||
notifyUpdate(newOp, nextVersion); | ||
}; | ||
propListeners.set(prop, propListener); | ||
} | ||
return propListener; | ||
}; | ||
var popPropListener = function popPropListener(prop) { | ||
var propListener = propListeners.get(prop); | ||
propListeners.delete(prop); | ||
return propListener; | ||
}; | ||
var createSnapshot = function createSnapshot(target, receiver) { | ||
@@ -120,3 +144,3 @@ var cache = snapshotCache.get(receiver); | ||
if (childListeners) { | ||
childListeners.delete(notifyUpdate); | ||
childListeners.delete(popPropListener(prop)); | ||
} | ||
@@ -127,3 +151,3 @@ | ||
if (deleted) { | ||
notifyUpdate(); | ||
notifyUpdate(['delete', [prop], prevValue]); | ||
} | ||
@@ -145,3 +169,3 @@ | ||
if (childListeners) { | ||
childListeners.delete(notifyUpdate); | ||
childListeners.delete(popPropListener(prop)); | ||
} | ||
@@ -154,7 +178,7 @@ | ||
target[prop][PROMISE_RESULT] = v; | ||
notifyUpdate(); | ||
notifyUpdate(['resolve', [prop], v]); | ||
return v; | ||
}).catch(function (e) { | ||
target[prop][PROMISE_ERROR] = e; | ||
notifyUpdate(); | ||
notifyUpdate(['reject', [prop], e]); | ||
}); | ||
@@ -170,6 +194,6 @@ } else { | ||
target[prop][LISTENERS].add(notifyUpdate); | ||
target[prop][LISTENERS].add(getPropListener(prop)); | ||
} | ||
notifyUpdate(); | ||
notifyUpdate(['set', [prop], value, prevValue]); | ||
return true; | ||
@@ -203,6 +227,9 @@ } | ||
var pendingVersion = 0; | ||
var ops = []; | ||
var listener = function listener(nextVersion) { | ||
var listener = function listener(op, nextVersion) { | ||
ops.push(op); | ||
if (notifyInSync) { | ||
callback(); | ||
callback(ops.splice(0)); | ||
return; | ||
@@ -214,3 +241,3 @@ } | ||
if (nextVersion === pendingVersion) { | ||
callback(); | ||
callback(ops.splice(0)); | ||
} | ||
@@ -217,0 +244,0 @@ }); |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
317
69116
31
1631