use-travel
Version:
A React hook for state time travel with undo, redo, reset, rebase and archive functionalities.
12 lines (11 loc) • 28.5 kB
JavaScript
import t,{useRef as e,useReducer as s,useEffect as i,useCallback as a,useMemo as n}from"react";import{create as r,apply as o,rawReturn as h,isDraft as c}from"mutative";"function"==typeof SuppressedError&&SuppressedError;class l extends Error{constructor(t,e,s={}){super(e),this.name="TravelsPersistenceError",this.code=t,this.cause=s.cause}}const p=t=>"object"==typeof t&&null!==t,u=t=>null==t||p(t)&&!Array.isArray(t),d=t=>{if(!p(t))return!1;const e=t.op;return!("add"!==e&&"remove"!==e&&"replace"!==e||!("string"==typeof(s=t.path)?""===s||s.startsWith("/"):Array.isArray(s)&&s.every(t=>"string"==typeof t||"number"==typeof t))||("add"===e||"remove"===e)&&(t=>""===t||Array.isArray(t)&&0===t.length)(t.path)||!("add"!==e&&"replace"!==e||(i=t,Object.prototype.hasOwnProperty.call(i,"value"))));var s,i},v=t=>Array.isArray(t)&&t.every(t=>Array.isArray(t)&&t.every(d)),m=t=>{if(!p(t))throw new l("INVALID_SCHEMA","Travels: persisted history must be an object.");if(1!==t.version)throw new l("UNSUPPORTED_VERSION",`Travels: unsupported persisted history version ${String(t.version)}. Expected 1.`);if(!("state"in t))throw new l("INVALID_SCHEMA","Travels: persisted history must include 'state'.");if(!("patches"in t))throw new l("INVALID_SCHEMA","Travels: persisted history must include 'patches'.");const e=t.patches,s=(t=>{if(!p(t))return"patches must be an object with 'patches' and 'inversePatches' arrays";const e=t;return v(e.patches)&&v(e.inversePatches)?e.patches.length!==e.inversePatches.length?"patches.patches and patches.inversePatches must have the same length":null:"patches must have 'patches' and 'inversePatches' arrays of JSON Patch operations"})(e);if(s)throw new l("INVALID_PATCHES",`Travels: ${s}.`);const i=t.position;if("number"!=typeof i||!Number.isFinite(i)||!Number.isInteger(i)||i<0||e&&i>e.patches.length)throw new l("INVALID_SCHEMA",`Travels: persisted history position ${String(i)} is invalid for the patch history.`);const a=t.metadata;let n;if(void 0!==a){if(!Array.isArray(a))throw new l("INVALID_SCHEMA","Travels: persisted history 'metadata' must be an array when provided.");const t=a;if(!t.every(u))throw new l("INVALID_SCHEMA","Travels: persisted history 'metadata' entries must be objects, null, or undefined.");n=t.map(t=>null==t?void 0:t)}if(void 0!==n&&n.length!==e.patches.length)throw new l("INVALID_SCHEMA","Travels: persisted history 'metadata' length must match patches length.");return{version:1,state:t.state,patches:e,position:i,metadata:n}};class y extends Error{constructor(t,e,s={}){super(e),this.name="TravelsError",this.code=t,this.cause=s.cause}}const f=t=>"object"==typeof t&&null!==t,g=t=>{if(!f(t))return!1;const e=Object.getPrototypeOf(t);return null===e||e===Object.prototype},P=t=>{if("function"==typeof globalThis.structuredClone)try{return globalThis.structuredClone(t)}catch(t){return}},b=(t,e=new WeakMap)=>{if(null===t||"object"!=typeof t)return t;if(e.has(t))return e.get(t);if(Array.isArray(t)){const s=new Array(t.length);e.set(t,s);for(let i=0;i<t.length;i+=1)Object.prototype.hasOwnProperty.call(t,i)&&(s[i]=b(t[i],e));return s}if(t instanceof Map){const s=new Map;return e.set(t,s),t.forEach((t,i)=>{s.set(b(i,e),b(t,e))}),s}if(t instanceof Set){const s=new Set;return e.set(t,s),t.forEach(t=>{s.add(b(t,e))}),s}if(t instanceof Date){const s=new Date(t.getTime());return e.set(t,s),s}const s=P(t);if(void 0!==s)return e.set(t,s),s;if(!g(t)&&null!==Object.getPrototypeOf(t))return t;const i={};e.set(t,i);for(const s in t)Object.prototype.hasOwnProperty.call(t,s)&&(i[s]=b(t[s],e));return i},S=t=>({patches:t?t.patches.map(t=>t.map(t=>b(t))):[],inversePatches:t?t.inversePatches.map(t=>t.map(t=>b(t))):[]}),E=t=>t?b(t):void 0,A=t=>t.map(E),O=(t,e)=>Array.from({length:e},(e,s)=>E(null==t?void 0:t[s])),w=(t,e)=>{if(e&&t&&"object"==typeof t){for(const s in t)Object.prototype.hasOwnProperty.call(t,s)&&(e[s]=b(t[s]));return e}return b(t)},M=t=>{if(null===t||"object"!=typeof t)return t;const e=P(t);return void 0!==e?e:w(t)},T=(t,e=new WeakSet)=>{if(!f(t))return!1;if(c(t))return!0;const s=t;if(e.has(s))return!1;if(e.add(s),t instanceof Map){for(const[s,i]of t)if(T(s,e)||T(i,e))return!0;return!1}if(t instanceof Set){for(const s of t)if(T(s,e))return!0;return!1}for(const t of Reflect.ownKeys(s))if(T(s[t],e))return!0;return!1},_=t=>!!Array.isArray(t)&&(!!Reflect.ownKeys(t).every(t=>{if("length"===t)return!0;if("symbol"==typeof t)return!1;const e=Number(t);return Number.isInteger(e)&&e>=0&&String(e)===t})&&Object.keys(t).length===t.length),N=t=>Array.isArray(t)&&t.every(t=>Array.isArray(t));class C{static deserialize(t,e){return((t,e={})=>{var s;try{const s=(t=>{if("string"!=typeof t)return t;try{return JSON.parse(t)}catch(t){throw new l("PARSE_ERROR","Travels: persisted history is not valid JSON.",{cause:t})}})(t);let i=s;if(e.migrate)try{i=e.migrate(s)}catch(t){throw new l("MIGRATION_FAILED","Travels: persisted history migration failed.",{cause:t})}return m(i)}catch(t){const i=t instanceof l?t:new l("INVALID_SCHEMA","Travels: persisted history could not be deserialized.",{cause:t});null===(s=e.onError)||void 0===s||s.call(e,i);const a=(t=>{if(t)return"function"==typeof t?t():t})(e.fallback);if(a)return m(a);throw i}})(t,e)}constructor(t,e={}){var s,i;this.listeners=new Set,this.pendingState=null,this.pendingStateVersion=0,this.controlsCache=null,this.historyCache=null,this.historyVersion=0,this.mutableFallbackWarned=!1,this.mutableRootReplaceWarned=!1,this.stateCompatibilityWarningKeys=new Set,this.trackingPauseDepth=0,this.transactionDepth=0,this.subscribe=t=>(this.listeners.add(t),()=>{this.listeners.delete(t)}),this.getState=()=>this.state;const{maxHistory:a=10,history:n,initialPatches:r,initialPosition:o=0,strictInitialPatches:h=!1,autoArchive:c=!0,mutable:l=!1,warnOnUnsupportedState:p="production"!==process.env.NODE_ENV,onError:u,onBranchDiscard:d,devtools:v,patchesOptions:m}=e,y=function(t,e){var s={};for(var i in t)Object.prototype.hasOwnProperty.call(t,i)&&e.indexOf(i)<0&&(s[i]=t[i]);if(null!=t&&"function"==typeof Object.getOwnPropertySymbols){var a=0;for(i=Object.getOwnPropertySymbols(t);a<i.length;a++)e.indexOf(i[a])<0&&Object.prototype.propertyIsEnumerable.call(t,i[a])&&(s[i[a]]=t[i[a]])}return s}(e,["maxHistory","history","initialPatches","initialPosition","strictInitialPatches","autoArchive","mutable","warnOnUnsupportedState","onError","onBranchDiscard","devtools","patchesOptions"]);let f=null!==(s=null==n?void 0:n.patches)&&void 0!==s?s:r,g=null!==(i=null==n?void 0:n.position)&&void 0!==i?i:o;if("production"!==process.env.NODE_ENV&&n&&(r||0!==o)&&console.warn("Travels: history overrides initialPatches and initialPosition."),"number"!=typeof a||!Number.isFinite(a)||!Number.isInteger(a))throw new Error(`Travels: maxHistory must be a non-negative integer, but got ${a}`);if(a<0)throw new Error(`Travels: maxHistory must be non-negative, but got ${a}`);0===a&&"production"!==process.env.NODE_ENV&&console.warn("Travels: maxHistory is 0, which disables undo/redo history. This is rarely intended.");const P=(t=>t?N(t.patches)&&N(t.inversePatches)?t.patches.length!==t.inversePatches.length?"initialPatches.patches and initialPatches.inversePatches must have the same length":null:"initialPatches must have 'patches' and 'inversePatches' arrays":null)(f);if(P){if(h)throw new Error(`Travels: ${P}`);"production"!==process.env.NODE_ENV&&console.warn(`Travels: ${P}. Falling back to empty history. Set strictInitialPatches: true to throw instead.`),f=void 0,g=0}this.state=t,this.initialState=M(t),this.maxHistory=a,this.autoArchive=c,this.mutable=l,this.warnOnUnsupportedState=p,this.onError=u,this.onBranchDiscard=d,this.devtools=v,this.options=Object.assign(Object.assign({},y),{enablePatches:null==m||m}),this.warnAboutStateCompatibility(t);const{patches:b,position:E,metadata:A}=this.normalizeInitialHistory(f,g,null==n?void 0:n.metadata);this.allPatches=b,this.allMetadata=A,this.initialPatches=f?S(b):void 0,this.initialMetadata=(null==n?void 0:n.metadata)?A.slice():void 0,this.position=E,this.initialPosition=E,this.tempPatches=S(),this.tempMetadata=void 0}warnAboutStateCompatibility(t){if(!this.warnOnUnsupportedState||"production"===process.env.NODE_ENV)return;const e=((t,e={})=>{var s;const i=null!==(s=e.maxIssues)&&void 0!==s?s:20,a=new WeakSet,n=[],r=(t,e,s)=>{var a;n.length>=i||n.push({code:t,path:(a=e,0===a.length?"$":a.reduce((t,e)=>"number"==typeof e?`${t}[${e}]`:`${t}.${e}`,"$")),message:s})},o=(t,s)=>{if(!(n.length>=i))if(void 0!==t)if("function"!=typeof t)if("symbol"!=typeof t){if(null!==t&&"object"==typeof t)if(a.has(t))r("CIRCULAR_REFERENCE",s,"circular references are not supported by JSON persistence.");else if(a.add(t),t instanceof Date)r("DATE",s,"Date values can be cloned, but JSON persistence restores them as strings; store timestamps or ISO strings explicitly.");else if(t instanceof WeakMap||t instanceof WeakSet)r("WEAK_COLLECTION",s,"WeakMap and WeakSet cannot be inspected, patched, or persisted safely.");else{if(t instanceof Map)return r(e.mutable?"MAP_SET_MUTABLE":"MAP_SET_PERSISTENCE",s,e.mutable?"Map is not supported in mutable mode; store entries as arrays or use immutable mode.":"Map works in immutable runtime mode, but JSON persistence requires a custom codec."),void t.forEach((t,e)=>{o(e,s.concat("<map-key>")),o(t,s.concat(String(e)))});if(t instanceof Set){r(e.mutable?"MAP_SET_MUTABLE":"MAP_SET_PERSISTENCE",s,e.mutable?"Set is not supported in mutable mode; store values as arrays or use immutable mode.":"Set works in immutable runtime mode, but JSON persistence requires a custom codec.");let i=0;return void t.forEach(t=>{o(t,s.concat(i)),i+=1})}if((t=>"undefined"!=typeof Node&&"object"==typeof t&&null!==t&&t instanceof Node)(t))r("DOM_NODE",s,"DOM nodes and refs should be stored outside Travels state.");else if(Array.isArray(t))t.forEach((t,e)=>o(t,s.concat(e)));else if((t=>{const e=Object.getPrototypeOf(t);return e===Object.prototype||null===e})(t))for(const e of Reflect.ownKeys(t))"symbol"!=typeof e?o(t[e],s.concat(e)):r("SYMBOL",s,"symbol keys cannot be represented in JSON Patch persistence.");else r("CLASS_INSTANCE",s,"class instances and custom prototypes lose methods/prototypes during JSON persistence.")}}else r("SYMBOL",s,"symbols cannot be represented in JSON Patch persistence.");else r("FUNCTION",s,"functions cannot be patched or persisted as state data.");else r("UNDEFINED",s,"undefined is removed by JSON persistence; use null for intentional empty values.")};return o(t,[]),n})(t,{mutable:this.mutable});for(const t of e){const e=`${t.code}:${t.path}`;this.stateCompatibilityWarningKeys.has(e)||(this.stateCompatibilityWarningKeys.add(e),console.warn(`Travels state compatibility warning at ${t.path}: ${t.message}`))}}normalizeInitialHistory(t,e,s){const i=S(t),a=i.patches.length,n=O(s,a),r=this.maxHistory>0?this.maxHistory:0,o="number"!=typeof e||!Number.isFinite(e)||!Number.isInteger(e);let h=o?0:e;const c=Math.max(0,Math.min(h,a));if("production"===process.env.NODE_ENV||!o&&c===h||console.warn(`Travels: initialPosition (${e}) is invalid for available patches (${a}). Using ${c} instead.`),h=c,0===a)return{patches:i,position:0,metadata:[]};if(0===r)return"production"!==process.env.NODE_ENV&&console.warn(`Travels: maxHistory (${this.maxHistory}) discards persisted history.`),{patches:S(),position:0,metadata:[]};if(r>=a)return{patches:i,position:h,metadata:n};const l=a-r,p=Math.min(h,l),u=p+r,d={patches:i.patches.slice(p,u),inversePatches:i.inversePatches.slice(p,u)},v=S(d),m=h-p;return"production"!==process.env.NODE_ENV&&console.warn(`Travels: initialPatches length (${a}) exceeds maxHistory (${r}). Retained ${r} steps from position ${p}. Position adjusted to ${m}.`),{patches:v,position:m,metadata:n.slice(p,u)}}invalidateHistoryCache(){this.historyVersion+=1,this.historyCache=null}getEventPatches(){if(this.listeners.size||this.devtools)return this.getPatches()}notify(t){if(!this.listeners.size)return;const e=null!=t?t:this.getPatches();this.listeners.forEach(t=>t(this.state,e,this.position))}emitDevtools(t,e,s){var i;if(!this.devtools)return;const a=null!=s?s:this.getPatches();null===(i=this.devtools)||void 0===i||i.call(this,{type:t,state:this.state,position:this.position,patches:a,metadata:e})}emitChange(t,e){const s=this.getEventPatches();this.notify(s),this.emitDevtools(t,e,s)}reportError(t,e){var s;const i=e instanceof y?e:new y(t,`Travels: ${t}`,{cause:e});return null===(s=this.onError)||void 0===s||s.call(this,i),i}toEntries(t,e=[]){return t.patches.map((s,i)=>({patches:s.map(t=>b(t)),inversePatches:t.inversePatches[i].map(t=>b(t)),metadata:E(e[i])}))}discardFutureFrom(t){var e;if(t>=this.allPatches.patches.length)return;const s={patches:this.allPatches.patches.slice(t),inversePatches:this.allPatches.inversePatches.slice(t)},i=A(this.allMetadata.slice(t));this.allPatches.patches.splice(t,this.allPatches.patches.length-t),this.allPatches.inversePatches.splice(t,this.allPatches.inversePatches.length-t),this.allMetadata.splice(t,this.allMetadata.length-t),null===(e=this.onBranchDiscard)||void 0===e||e.call(this,{position:t,discarded:this.toEntries(s,i)})}trimHistoryToMax(){if(!(this.maxHistory>=this.allPatches.patches.length)){if(0===this.maxHistory)return this.allPatches.patches=[],this.allPatches.inversePatches=[],void(this.allMetadata=[]);this.allPatches.patches=this.allPatches.patches.slice(-this.maxHistory),this.allPatches.inversePatches=this.allPatches.inversePatches.slice(-this.maxHistory),this.allMetadata=A(this.allMetadata.slice(-this.maxHistory))}}resetHistoryToCurrentState(){this.initialState=M(this.state),this.initialPosition=0,this.initialPatches=void 0,this.initialMetadata=void 0,this.position=0,this.allPatches=S(),this.allMetadata=[],this.tempPatches=S(),this.tempMetadata=void 0}hasRecordedHistory(){var t,e,s;return 0!==this.position||0!==this.initialPosition||!!(null===(t=this.initialPatches)||void 0===t?void 0:t.patches.length)||!!(null===(e=this.initialPatches)||void 0===e?void 0:e.inversePatches.length)||!!(null===(s=this.initialMetadata)||void 0===s?void 0:s.length)||this.allPatches.patches.length>0||this.allPatches.inversePatches.length>0||this.allMetadata.length>0||this.tempPatches.patches.length>0||this.tempPatches.inversePatches.length>0||void 0!==this.tempMetadata}restoreStateFromSnapshot(t){if(this.mutable&&f(this.state)&&f(t)){const[,e]=r(this.state,e=>{for(const t of Object.keys(e))delete e[t];w(t,e),Array.isArray(e)&&Array.isArray(t)&&(e.length=t.length)},this.options);return void o(this.state,e,{mutable:!0})}this.state=t}captureTransactionSnapshot(){return{state:this.mutable&&f(this.state)?M(this.state):this.state,position:this.position,allPatches:S(this.allPatches),allMetadata:A(this.allMetadata),tempPatches:S(this.tempPatches),tempMetadata:E(this.tempMetadata),initialState:M(this.initialState),initialPosition:this.initialPosition,initialPatches:this.initialPatches?S(this.initialPatches):void 0,initialMetadata:this.initialMetadata?A(this.initialMetadata):void 0,pendingState:this.pendingState,pendingStateVersion:this.pendingStateVersion}}restoreTransactionSnapshot(t){this.restoreStateFromSnapshot(t.state),this.position=t.position,this.allPatches=S(t.allPatches),this.allMetadata=A(t.allMetadata),this.tempPatches=S(t.tempPatches),this.tempMetadata=E(t.tempMetadata),this.initialState=M(t.initialState),this.initialPosition=t.initialPosition,this.initialPatches=t.initialPatches?S(t.initialPatches):void 0,this.initialMetadata=t.initialMetadata?A(t.initialMetadata):void 0,this.pendingState=t.pendingState,this.pendingStateVersion=t.pendingStateVersion,this.invalidateHistoryCache(),this.notify()}hasRootReplacement(t){return t.some(t=>(Array.isArray(t.path)&&0===t.path.length||""===t.path)&&"replace"===t.op)}setState(t,e){let s,i,a;const n=this.mutable&&f(this.state),c="function"==typeof t,l=Array.isArray(this.state),p=Array.isArray(t),u=!l&&!p&&g(this.state)&&g(t),d=l&&p&&_(this.state)&&_(t),v=c&&n||n&&!c&&(d||u);if(!this.mutable||n||this.mutableFallbackWarned||(this.mutableFallbackWarned=!0,"production"!==process.env.NODE_ENV&&console.warn("Travels: mutable mode requires the state root to be an object. Falling back to immutable updates.")),v){const[e,n,h]=r(this.state,c?t:e=>{((t,e)=>{const s=Array.isArray(t),i=Array.isArray(e),a=Reflect.ownKeys(t);for(const i of a)s&&"length"===i||Object.prototype.hasOwnProperty.call(e,i)||delete t[i];s&&i&&(t.length=e.length),Object.assign(t,e)})(e,t)},this.options);s=n,i=h,this.hasRootReplacement(s)?("production"===process.env.NODE_ENV||this.mutableRootReplaceWarned||(this.mutableRootReplaceWarned=!0,console.warn("Travels: mutable mode cannot apply root replacements in place. Falling back to immutable update for this change.")),this.state=e,a=e):(o(this.state,s,{mutable:!0}),a=this.state)}else{const[e,n,o]=r(this.state,"function"==typeof t?e=>{const s=t(e);return s===e?s:f(s)&&!T(s)?h(s):s}:()=>f(t)?h(t):t,this.options);s=n,i=o,this.state=e,a=e}if(0===s.length&&0===i.length)return;this.pendingState=a;const m=++this.pendingStateVersion;if(Promise.resolve().then(()=>{this.pendingStateVersion===m&&(this.pendingState=null)}),this.warnAboutStateCompatibility(this.state),this.trackingPauseDepth>0)return this.resetHistoryToCurrentState(),this.invalidateHistoryCache(),void this.emitChange("replaceStateWithoutHistory",e);if(this.autoArchive)this.position<this.allPatches.patches.length&&this.discardFutureFrom(this.position),this.allPatches.patches.push(s),this.allPatches.inversePatches.push(i),this.allMetadata.push(E(e)),this.position=this.maxHistory<this.allPatches.patches.length?this.maxHistory:this.position+1,this.trimHistoryToMax();else{const t=this.position<this.allPatches.patches.length+Number(!!this.tempPatches.patches.length);t&&this.discardFutureFrom(this.position),this.tempPatches.patches.length&&!t||(this.position=this.maxHistory<this.allPatches.patches.length+1?this.maxHistory:this.position+1),t&&(this.tempPatches.patches.length=0,this.tempPatches.inversePatches.length=0,this.tempMetadata=void 0),this.tempPatches.patches.push(s),this.tempPatches.inversePatches.push(i),void 0===e&&void 0!==this.tempMetadata||(this.tempMetadata=E(e))}this.invalidateHistoryCache(),this.emitChange("setState",e)}archivePending(t){if(!this.tempPatches.patches.length)return!1;const e=void 0===t?this.tempMetadata:t,s=this.getPendingArchiveEntry();return this.allPatches.patches.push(s.patches),this.allPatches.inversePatches.push(s.inversePatches),this.allMetadata.push(E(e)),this.trimHistoryToMax(),this.tempPatches.patches.length=0,this.tempPatches.inversePatches.length=0,this.tempMetadata=void 0,this.invalidateHistoryCache(),this.emitChange("archive",e),!0}archive(t){this.autoArchive?console.warn("Auto archive is enabled, no need to archive manually"):this.archivePending(t)}transaction(t,e){const s="function"==typeof t?void 0:E(t),i="function"==typeof t?t:e;if(!i)return;const a=this.autoArchive,n=this.transactionMetadata,r=0===this.transactionDepth,o=this.captureTransactionSnapshot();let h=!1;this.transactionDepth+=1,(r||!this.transactionMetadata&&s)&&(this.transactionMetadata=s),this.autoArchive=!1;try{i()}catch(t){throw h=!0,this.restoreTransactionSnapshot(o),this.transactionMetadata=n,this.reportError("TRANSACTION_FAILED",t)}finally{this.transactionDepth-=1,0===this.transactionDepth&&(this.autoArchive=a,h||this.archivePending(this.transactionMetadata)&&this.emitDevtools("transaction",this.transactionMetadata),this.transactionMetadata=n)}}batch(t,e){this.transaction(t,e)}pauseTracking(){this.trackingPauseDepth+=1}resumeTracking(){this.trackingPauseDepth=Math.max(0,this.trackingPauseDepth-1)}replaceStateWithoutHistory(t){const e=this.historyVersion;this.pauseTracking();try{this.setState(t)}finally{this.resumeTracking()}this.historyVersion===e&&(this.hasRecordedHistory()||this.mutable)&&(this.resetHistoryToCurrentState(),this.invalidateHistoryCache(),this.emitChange("replaceStateWithoutHistory"))}getPendingArchiveEntry(){var t;const e=null!==(t=this.pendingState)&&void 0!==t?t:this.state,s=o(e,this.tempPatches.inversePatches.flat().reverse()),[,i,a]=r(e,()=>f(s)?h(s):s,this.options);return{patches:a,inversePatches:i}}getAllPatches(){if(!this.autoArchive&&this.tempPatches.patches.length){const t=this.getPendingArchiveEntry();return{patches:this.allPatches.patches.concat([t.patches]),inversePatches:this.allPatches.inversePatches.concat([t.inversePatches])}}return this.allPatches}getHistory(){if(this.historyCache&&this.historyCache.version===this.historyVersion)return this.historyCache.history;let t=this.state;const e=this.getAllPatches(),s=!this.autoArchive&&e.patches.length>this.maxHistory?e.patches.slice(e.patches.length-this.maxHistory):e.patches,i=!this.autoArchive&&e.inversePatches.length>this.maxHistory?e.inversePatches.slice(e.inversePatches.length-this.maxHistory):e.inversePatches,a=[];for(let e=this.position;e<s.length;e++)t=o(t,s[e]),a.push(t);t=this.state;const n=[];for(let e=this.position-1;e>-1;e--)t=o(t,i[e]),n.push(t);n.reverse();const r=[...n,this.state,...a];return this.historyCache={version:this.historyVersion,history:r},"production"!==process.env.NODE_ENV&&Object.freeze(r),r}go(t){if("number"!=typeof t||!Number.isFinite(t))return void console.warn(`Can't go to invalid position ${t}`);if(!Number.isInteger(t)){const e=Math.trunc(t);console.warn(`Can't go to non-integer position ${t}. Using ${e} instead.`),t=e}const e=!this.autoArchive&&!!this.tempPatches.patches.length;e&&this.archive();const s=this.getAllPatches(),i=t<this.position;if(t>s.patches.length&&(console.warn(`Can't go forward to position ${t}`),t=s.patches.length),t<0&&(console.warn(`Can't go back to position ${t}`),t=0),t===this.position)return;const a=e&&s.inversePatches.length>0?s.inversePatches.map((t,e,s)=>e===s.length-1?[...t].reverse():t):s.inversePatches,n=i?a.slice(-this.maxHistory).slice(t,this.position).flat().reverse():s.patches.slice(-this.maxHistory).slice(this.position,t).flat();this.mutable&&f(this.state)&&!this.hasRootReplacement(n)?o(this.state,n,{mutable:!0}):this.state=o(this.state,n),this.position=t,this.invalidateHistoryCache(),this.emitChange("go")}back(t=1){this.go(this.position-t)}forward(t=1){this.go(this.position+t)}reset(){if(this.mutable&&f(this.state)&&f(this.initialState)){const[,t]=r(this.state,t=>{for(const e of Object.keys(t))delete t[e];w(this.initialState,t),Array.isArray(t)&&Array.isArray(this.initialState)&&(t.length=this.initialState.length)},this.options);o(this.state,t,{mutable:!0})}else this.state=M(this.initialState);this.position=this.initialPosition,this.allPatches=S(this.initialPatches),this.allMetadata=this.initialMetadata?A(this.initialMetadata):[],this.tempPatches=S(),this.tempMetadata=void 0,this.invalidateHistoryCache(),this.emitChange("reset")}rebase(){this.initialState=M(this.state),this.initialPosition=0,this.initialPatches=void 0,this.initialMetadata=void 0,this.position=0,this.allPatches=S(),this.allMetadata=[],this.tempPatches=S(),this.tempMetadata=void 0,this.invalidateHistoryCache(),this.emitChange("rebase")}canBack(){return this.position>0}canForward(){const t=!this.autoArchive&&!!this.tempPatches.patches.length,e=this.getAllPatches();return t?this.position<e.patches.length-1:this.position<e.patches.length}canArchive(){return!this.autoArchive&&!!this.tempPatches.patches.length}getPosition(){return this.position}getPatches(){const t=!this.autoArchive&&this.tempPatches.patches.length?this.getAllPatches():this.allPatches;return S(t)}serialize(){return{version:1,state:M(this.state),patches:this.getPatches(),position:this.getPosition(),metadata:this.getMetadata()}}getMetadata(){const t=O(this.allMetadata,this.allPatches.patches.length);return!this.autoArchive&&this.tempPatches.patches.length&&t.push(E(this.tempMetadata)),t}getHistoryEntries(){return this.toEntries(this.getPatches(),this.getMetadata())}getControls(){if(this.controlsCache)return this.controlsCache;const t=this,e={get position(){return t.getPosition()},getHistory:()=>t.getHistory(),get patches(){return t.getPatches()},back:e=>t.back(e),forward:e=>t.forward(e),reset:()=>t.reset(),go:e=>t.go(e),canBack:()=>t.canBack(),canForward:()=>t.canForward(),rebase:()=>t.rebase()};return this.autoArchive||(e.archive=e=>t.archive(e),e.canArchive=()=>t.canArchive()),"production"!==process.env.NODE_ENV&&Object.freeze(e),this.controlsCache=e,e}}var H,D={exports:{}},x={};var I,V,j={};
/**
* @license React
* use-sync-external-store-shim.development.js
*
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/var k=(V||(V=1,"production"===process.env.NODE_ENV?D.exports=function(){if(H)return x;H=1;var e=t,s="function"==typeof Object.is?Object.is:function(t,e){return t===e&&(0!==t||1/t==1/e)||t!=t&&e!=e},i=e.useState,a=e.useEffect,n=e.useLayoutEffect,r=e.useDebugValue;function o(t){var e=t.getSnapshot;t=t.value;try{var i=e();return!s(t,i)}catch(t){return!0}}var h="undefined"==typeof window||void 0===window.document||void 0===window.document.createElement?function(t,e){return e()}:function(t,e){var s=e(),h=i({inst:{value:s,getSnapshot:e}}),c=h[0].inst,l=h[1];return n(function(){c.value=s,c.getSnapshot=e,o(c)&&l({inst:c})},[t,s,e]),a(function(){return o(c)&&l({inst:c}),t(function(){o(c)&&l({inst:c})})},[t]),r(s),s};return x.useSyncExternalStore=void 0!==e.useSyncExternalStore?e.useSyncExternalStore:h,x}():D.exports=(I||(I=1,"production"!==process.env.NODE_ENV&&function(){function e(t){var e=t.getSnapshot;t=t.value;try{var s=e();return!i(t,s)}catch(t){return!0}}"undefined"!=typeof __REACT_DEVTOOLS_GLOBAL_HOOK__&&"function"==typeof __REACT_DEVTOOLS_GLOBAL_HOOK__.registerInternalModuleStart&&__REACT_DEVTOOLS_GLOBAL_HOOK__.registerInternalModuleStart(Error());var s=t,i="function"==typeof Object.is?Object.is:function(t,e){return t===e&&(0!==t||1/t==1/e)||t!=t&&e!=e},a=s.useState,n=s.useEffect,r=s.useLayoutEffect,o=s.useDebugValue,h=!1,c=!1,l="undefined"==typeof window||void 0===window.document||void 0===window.document.createElement?function(t,e){return e()}:function(t,l){h||void 0===s.startTransition||(h=!0,console.error("You are using an outdated, pre-release alpha of React 18 that does not support useSyncExternalStore. The use-sync-external-store shim will not work correctly. Upgrade to a newer pre-release."));var p=l();if(!c){var u=l();i(p,u)||(console.error("The result of getSnapshot should be cached to avoid an infinite loop"),c=!0)}var d=(u=a({inst:{value:p,getSnapshot:l}}))[0].inst,v=u[1];return r(function(){d.value=p,d.getSnapshot=l,e(d)&&v({inst:d})},[t,p,l]),n(function(){return e(d)&&v({inst:d}),t(function(){e(d)&&v({inst:d})})},[t]),o(p),p};j.useSyncExternalStore=void 0!==s.useSyncExternalStore?s.useSyncExternalStore:l,"undefined"!=typeof __REACT_DEVTOOLS_GLOBAL_HOOK__&&"function"==typeof __REACT_DEVTOOLS_GLOBAL_HOOK__.registerInternalModuleStop&&__REACT_DEVTOOLS_GLOBAL_HOOK__.registerInternalModuleStop(Error())}()),j)),D.exports);function R(t,r={}){const o=e(null);o.current||(o.current=new C(t,Object.assign(Object.assign({},r),{mutable:!1})));const[,h]=s(t=>t+1,0),c=e(!1);i(()=>{c.current=!1}),i(()=>o.current.subscribe(()=>{h()}),[]);const l=o.current,p=a(t=>{if(c.current)throw new Error("setState cannot be called multiple times in the same render cycle.");c.current=!0,l.setState(t)},[l]);return[l.getState(),p,n(()=>{const t=l.getControls();return{get position(){return l.getPosition()},getHistory:()=>t.getHistory(),get patches(){return l.getPatches()},back:e=>t.back(e),forward:e=>t.forward(e),reset:()=>t.reset(),go:e=>t.go(e),canBack:()=>t.canBack(),canForward:()=>t.canForward(),get canUndo(){return t.canBack()},get canRedo(){return t.canForward()},rebase:()=>t.rebase(),archive:()=>{"archive"in t?t.archive():l.archive()},canArchive:()=>"canArchive"in t?t.canArchive():l.canArchive()}},[l])]}function L(t){if(Boolean(null==t?void 0:t.mutable))throw new Error("useTravelStore only supports immutable Travels instances. Remove `mutable: true` or use useTravel instead.");return[k.useSyncExternalStore(t.subscribe,t.getState,t.getState),a(e=>t.setState(e),[t]),n(()=>{const e=t.getControls();return Object.defineProperties({},Object.assign(Object.assign({},Object.getOwnPropertyDescriptors(e)),{canUndo:{get:()=>e.canBack(),enumerable:!0},canRedo:{get:()=>e.canForward(),enumerable:!0}}))},[t])]}export{R as useTravel,L as useTravelStore};
//# sourceMappingURL=index.esm.js.map