diff --git a/lib/useDataHistory/useDataHistory.ts b/lib/useDataHistory/useDataHistory.ts new file mode 100644 index 0000000..6a5d08f --- /dev/null +++ b/lib/useDataHistory/useDataHistory.ts @@ -0,0 +1,67 @@ +import { useReducer } from 'react'; + +interface State { + past: T[]; + data: T; + future: T[]; +} + +interface Action { + type: string; + value?: T; +} + +const ACTION_TYPES = { + CHANGE: 'CHANGE', + UNDO: 'UNDO', + REDO: 'REDO', +} as const; + +const getDefaultState = (value: T): State => ({ past: [], data: value, future: [] }); + +const reducer = (state: State, action: Action): State => { + const { past, data, future } = state; + switch (action.type) { + case ACTION_TYPES.CHANGE: + return { + past: [...past, data], + data: action.value as T, + future: [], + }; + case ACTION_TYPES.UNDO: + if (past.length === 0) return state; + return { + past: past.slice(0, -1), + data: past[past.length - 1], + future: [data, ...future], + }; + case ACTION_TYPES.REDO: + if (future.length === 0) return state; + return { + past: [...past, data], + data: future[0], + future: future.slice(1), + }; + default: + return state; + } +}; + +export function useHistory(initialValue: T) { + const [state, dispatch] = useReducer(reducer, getDefaultState(initialValue)); + const { past, data, future } = state; + + const redo = () => { + dispatch({ type: ACTION_TYPES.REDO }); + }; + + const set = (value: T) => { + dispatch({ type: ACTION_TYPES.CHANGE, value }); + }; + + const undo = () => { + dispatch({ type: ACTION_TYPES.UNDO }); + }; + + return { data, history: { past, future }, actions: { redo, set, undo } }; +} diff --git a/package.json b/package.json index 7f0e781..f39e4b3 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "@spiffdog/spiffy-hooks", "private": false, - "version": "0.0.6-3", + "version": "0.0.6-4", "description": "", "type": "module", "main": "dist/index.cjs.js",