UNPKG

jotai-history

Version:
95 lines • 3.32 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.withUndo = withUndo; const vanilla_1 = require("jotai/vanilla"); const actions_1 = require("./actions.js"); /** * @param targetAtom a primitive atom or equivalent * @param limit the maximum number of history states to keep * @returns an atom with undo/redo capabilities */ function withUndo(historyAtom, targetAtom, limit, getArgs) { const createRef = () => ({ index: 0, stack: [], action: null, }); const refreshAtom = (0, vanilla_1.atom)(0); const refAtom = (0, vanilla_1.atom)(createRef, (get, set, action) => { if (action === actions_1.RESET) { void Object.assign(get(refAtom), createRef()); set(refreshAtom, (v) => v + 1); } }); refAtom.onMount = (setAtom) => () => setAtom(actions_1.RESET); refAtom.debugPrivate = true; const updateRefAtom = (0, vanilla_1.atom)((get) => { const history = get(historyAtom); const ref = get(refAtom); get(refreshAtom); if (ref.action) { // recalculation caused by undo/redo/reset ref.action = null; } else { // Remove future states if any ref.stack = ref.stack.slice(0, ref.index + 1); // Push the current state to the stack ref.stack.push(history[0]); // Limit the stack ref.stack = ref.stack.slice(-limit); // Move the current index to the end ref.index = ref.stack.length - 1; } return Object.assign({}, ref); }, (get, set) => { const ref = get(refAtom); ref.stack = [get(targetAtom)]; return () => set(refAtom, actions_1.RESET); }); updateRefAtom.onMount = (mount) => mount(); updateRefAtom.debugPrivate = true; const canUndoAtom = (0, vanilla_1.atom)((get) => { return get(updateRefAtom).index > 0; }); const canRedoAtom = (0, vanilla_1.atom)((get) => { const ref = get(updateRefAtom); return ref.index < ref.stack.length - 1; }); return (0, vanilla_1.atom)((get) => ({ canUndo: get(canUndoAtom), canRedo: get(canRedoAtom), }), (get, set, action) => { const ref = get(refAtom); const setCurrentState = (index) => { if (index in ref.stack) { const value = ref.stack[index]; const args = typeof getArgs === 'function' ? getArgs(value) : [value]; set(targetAtom, ...args); } }; if (action === actions_1.UNDO) { if (get(canUndoAtom)) { ref.action = actions_1.UNDO; get(historyAtom).shift(); setCurrentState(--ref.index); get(historyAtom).shift(); } } else if (action === actions_1.REDO) { if (get(canRedoAtom)) { ref.action = actions_1.REDO; setCurrentState(++ref.index); } } else if (action === actions_1.RESET) { ref.action = actions_1.RESET; set(refAtom, action); } else { return; } set(refreshAtom, (v) => v + 1); }); } //# sourceMappingURL=withUndo.js.map