use-travel
Version:
A React hook for state time travel with undo, redo, reset and archive functionalities.
3 lines (2 loc) • 3.54 kB
JavaScript
import{useRef as e,useEffect as t,useState as s,useCallback as c,useMemo as n}from"react";import{create as a,apply as h}from"mutative";function r(n,h){e({patches:[],inversePatches:[]});const r=e(0),i=e(0);let l=r.current;t((()=>{r.current=l,i.current=l})),l+=1,i.current+=1;const[p,o]=s((()=>"function"==typeof n?n():n)),v=c((e=>{o((t=>a(t,"function"==typeof e?e:()=>e,h)))}),[]);return t((()=>{})),[p,v]}"function"==typeof SuppressedError&&SuppressedError;const i=(e,t={})=>{const{maxHistory:i=10,initialPatches:l,initialPosition:p=0,autoArchive:o=!0}=t,v=function(e,t){var s={};for(var c in e)Object.prototype.hasOwnProperty.call(e,c)&&t.indexOf(c)<0&&(s[c]=e[c]);if(null!=e&&"function"==typeof Object.getOwnPropertySymbols){var n=0;for(c=Object.getOwnPropertySymbols(e);n<c.length;n++)t.indexOf(c[n])<0&&Object.prototype.propertyIsEnumerable.call(e,c[n])&&(s[c[n]]=e[c[n]])}return s}(t,["maxHistory","initialPatches","initialPosition","autoArchive"]),[u,P]=s(p),[g,f]=r((()=>({patches:[],inversePatches:[]}))),[y,b]=r((()=>null!=l?l:{patches:[],inversePatches:[]})),[m,O]=s(e),d=c((e=>{const[t,s,c]=a(m,"function"==typeof e?e:()=>e,Object.assign(Object.assign({},v),{enablePatches:!0}));if(O(t),o)P(i<y.patches.length+1?i:u+1),b((e=>{u<e.patches.length&&(e.patches.splice(u,e.patches.length-u),e.inversePatches.splice(u,e.inversePatches.length-u)),e.patches.push(s),e.inversePatches.push(c),i<e.patches.length&&(e.patches=e.patches.slice(-i),e.inversePatches=e.inversePatches.slice(-i))}));else{const e=u<y.patches.length+Number(!!g.patches.length);e&&(y.patches.splice(u,y.patches.length-u),y.inversePatches.splice(u,y.inversePatches.length-u)),g.patches.length&&!e||P(i<y.patches.length+1?i:u+1),f((t=>{e&&(t.patches.length=0,t.inversePatches.length=0),t.patches.push(s),t.inversePatches.push(c)}))}}),[y,m,u,f]),w=()=>{o?console.warn("Auto archive is enabled, no need to archive manually"):g.patches.length&&(b((e=>{const[,t,s]=a(m,(e=>h(e,g.inversePatches.flat().reverse())),{enablePatches:!0});e.patches.push(s),e.inversePatches.push(t),i<e.patches.length&&(e.patches=e.patches.slice(-i),e.inversePatches=e.inversePatches.slice(-i))})),f((e=>{e.patches.length=0,e.inversePatches.length=0})))},j=n((()=>!o&&!!g.patches.length),[g]),x=n((()=>{let e=y;return j&&(e={patches:y.patches.concat(),inversePatches:y.inversePatches.concat()},e.patches.push(g.patches.flat()),e.inversePatches.push(g.inversePatches.flat().reverse())),e}),[y,g,j]),A=n((()=>{const t=e=>{const t=e<u;j&&w(),e>x.patches.length&&(console.warn(`Can't go forward to position ${e}`),e=x.patches.length),e<0&&(console.warn(`Can't go back to position ${e}`),e=0),e!==u&&(j&&x.inversePatches.slice(-1)[0].reverse(),O((()=>h(m,t?x.inversePatches.slice(-i).slice(e).flat().reverse():x.patches.slice(-i).slice(u,e).flat()))),P(e))};let s;return{position:u,getHistory:()=>{if(s)return s;s=[m];let e=m;const t=!o&&x.patches.length>i?x.patches.slice(x.patches.length-i):x.patches,c=!o&&x.inversePatches.length>i?x.inversePatches.slice(x.inversePatches.length-i):x.inversePatches;for(let c=u;c<t.length;c++)e=h(e,t[c]),s.push(e);e=m;for(let t=u-1;t>-1;t--)e=h(e,c[t]),s.unshift(e);return s},patches:j?x:y,back:(e=1)=>{t(u-e)},forward:(e=1)=>{t(u+e)},reset:()=>{P(p),b((()=>null!=l?l:{patches:[],inversePatches:[]})),O((()=>e)),f((()=>({patches:[],inversePatches:[]})))},go:t,canBack:()=>u>0,canForward:()=>j?u<x.patches.length-1:u<y.patches.length,canArchive:()=>j,archive:w}}),[u,y,P,b,O,e,m,g,x,j]);return[m,d,A]};export{i as useTravel};
//# sourceMappingURL=index.esm.js.map