use-travel
Version:
A React hook for state time travel with undo, redo, reset, rebase and archive functionalities.
12 lines (11 loc) • 28.6 kB
JavaScript
"use strict";var t=require("react"),e=require("mutative");"function"==typeof SuppressedError&&SuppressedError;class s extends Error{constructor(t,e,s={}){super(e),this.name="TravelsPersistenceError",this.code=t,this.cause=s.cause}}const i=t=>"object"==typeof t&&null!==t,a=t=>null==t||i(t)&&!Array.isArray(t),r=t=>{if(!i(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||(a=t,Object.prototype.hasOwnProperty.call(a,"value"))));var s,a},n=t=>Array.isArray(t)&&t.every(t=>Array.isArray(t)&&t.every(r)),o=t=>{if(!i(t))throw new s("INVALID_SCHEMA","Travels: persisted history must be an object.");if(1!==t.version)throw new s("UNSUPPORTED_VERSION",`Travels: unsupported persisted history version ${String(t.version)}. Expected 1.`);if(!("state"in t))throw new s("INVALID_SCHEMA","Travels: persisted history must include 'state'.");if(!("patches"in t))throw new s("INVALID_SCHEMA","Travels: persisted history must include 'patches'.");const e=t.patches,r=(t=>{if(!i(t))return"patches must be an object with 'patches' and 'inversePatches' arrays";const e=t;return n(e.patches)&&n(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(r)throw new s("INVALID_PATCHES",`Travels: ${r}.`);const o=t.position;if("number"!=typeof o||!Number.isFinite(o)||!Number.isInteger(o)||o<0||e&&o>e.patches.length)throw new s("INVALID_SCHEMA",`Travels: persisted history position ${String(o)} is invalid for the patch history.`);const h=t.metadata;let c;if(void 0!==h){if(!Array.isArray(h))throw new s("INVALID_SCHEMA","Travels: persisted history 'metadata' must be an array when provided.");const t=h;if(!t.every(a))throw new s("INVALID_SCHEMA","Travels: persisted history 'metadata' entries must be objects, null, or undefined.");c=t.map(t=>null==t?void 0:t)}if(void 0!==c&&c.length!==e.patches.length)throw new s("INVALID_SCHEMA","Travels: persisted history 'metadata' length must match patches length.");return{version:1,state:t.state,patches:e,position:o,metadata:c}};class h extends Error{constructor(t,e,s={}){super(e),this.name="TravelsError",this.code=t,this.cause=s.cause}}const c=t=>"object"==typeof t&&null!==t,l=t=>{if(!c(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}},u=(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]=u(t[i],e));return s}if(t instanceof Map){const s=new Map;return e.set(t,s),t.forEach((t,i)=>{s.set(u(i,e),u(t,e))}),s}if(t instanceof Set){const s=new Set;return e.set(t,s),t.forEach(t=>{s.add(u(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(!l(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]=u(t[s],e));return i},d=t=>({patches:t?t.patches.map(t=>t.map(t=>u(t))):[],inversePatches:t?t.inversePatches.map(t=>t.map(t=>u(t))):[]}),v=t=>t?u(t):void 0,y=t=>t.map(v),m=(t,e)=>Array.from({length:e},(e,s)=>v(null==t?void 0:t[s])),f=(t,e)=>{if(e&&t&&"object"==typeof t){for(const s in t)Object.prototype.hasOwnProperty.call(t,s)&&(e[s]=u(t[s]));return e}return u(t)},g=t=>{if(null===t||"object"!=typeof t)return t;const e=p(t);return void 0!==e?e:f(t)},P=(t,s=new WeakSet)=>{if(!c(t))return!1;if(e.isDraft(t))return!0;const i=t;if(s.has(i))return!1;if(s.add(i),t instanceof Map){for(const[e,i]of t)if(P(e,s)||P(i,s))return!0;return!1}if(t instanceof Set){for(const e of t)if(P(e,s))return!0;return!1}for(const t of Reflect.ownKeys(i))if(P(i[t],s))return!0;return!1},b=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),S=t=>Array.isArray(t)&&t.every(t=>Array.isArray(t));class E{static deserialize(t,e){return((t,e={})=>{var i;try{const i=(t=>{if("string"!=typeof t)return t;try{return JSON.parse(t)}catch(t){throw new s("PARSE_ERROR","Travels: persisted history is not valid JSON.",{cause:t})}})(t);let a=i;if(e.migrate)try{a=e.migrate(i)}catch(t){throw new s("MIGRATION_FAILED","Travels: persisted history migration failed.",{cause:t})}return o(a)}catch(t){const a=t instanceof s?t:new s("INVALID_SCHEMA","Travels: persisted history could not be deserialized.",{cause:t});null===(i=e.onError)||void 0===i||i.call(e,a);const r=(t=>{if(t)return"function"==typeof t?t():t})(e.fallback);if(r)return o(r);throw a}})(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:r,initialPatches:n,initialPosition:o=0,strictInitialPatches:h=!1,autoArchive:c=!0,mutable:l=!1,warnOnUnsupportedState:p="production"!==process.env.NODE_ENV,onError:u,onBranchDiscard:v,devtools:y,patchesOptions:m}=e,f=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 P=null!==(s=null==r?void 0:r.patches)&&void 0!==s?s:n,b=null!==(i=null==r?void 0:r.position)&&void 0!==i?i:o;if("production"!==process.env.NODE_ENV&&r&&(n||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 E=(t=>t?S(t.patches)&&S(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)(P);if(E){if(h)throw new Error(`Travels: ${E}`);"production"!==process.env.NODE_ENV&&console.warn(`Travels: ${E}. Falling back to empty history. Set strictInitialPatches: true to throw instead.`),P=void 0,b=0}this.state=t,this.initialState=g(t),this.maxHistory=a,this.autoArchive=c,this.mutable=l,this.warnOnUnsupportedState=p,this.onError=u,this.onBranchDiscard=v,this.devtools=y,this.options=Object.assign(Object.assign({},f),{enablePatches:null==m||m}),this.warnAboutStateCompatibility(t);const{patches:A,position:O,metadata:w}=this.normalizeInitialHistory(P,b,null==r?void 0:r.metadata);this.allPatches=A,this.allMetadata=w,this.initialPatches=P?d(A):void 0,this.initialMetadata=(null==r?void 0:r.metadata)?w.slice():void 0,this.position=O,this.initialPosition=O,this.tempPatches=d(),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,r=[],n=(t,e,s)=>{var a;r.length>=i||r.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(!(r.length>=i))if(void 0!==t)if("function"!=typeof t)if("symbol"!=typeof t){if(null!==t&&"object"==typeof t)if(a.has(t))n("CIRCULAR_REFERENCE",s,"circular references are not supported by JSON persistence.");else if(a.add(t),t instanceof Date)n("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)n("WEAK_COLLECTION",s,"WeakMap and WeakSet cannot be inspected, patched, or persisted safely.");else{if(t instanceof Map)return n(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){n(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))n("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)):n("SYMBOL",s,"symbol keys cannot be represented in JSON Patch persistence.");else n("CLASS_INSTANCE",s,"class instances and custom prototypes lose methods/prototypes during JSON persistence.")}}else n("SYMBOL",s,"symbols cannot be represented in JSON Patch persistence.");else n("FUNCTION",s,"functions cannot be patched or persisted as state data.");else n("UNDEFINED",s,"undefined is removed by JSON persistence; use null for intentional empty values.")};return o(t,[]),r})(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=d(t),a=i.patches.length,r=m(s,a),n=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===n)return"production"!==process.env.NODE_ENV&&console.warn(`Travels: maxHistory (${this.maxHistory}) discards persisted history.`),{patches:d(),position:0,metadata:[]};if(n>=a)return{patches:i,position:h,metadata:r};const l=a-n,p=Math.min(h,l),u=p+n,v={patches:i.patches.slice(p,u),inversePatches:i.inversePatches.slice(p,u)},y=d(v),f=h-p;return"production"!==process.env.NODE_ENV&&console.warn(`Travels: initialPatches length (${a}) exceeds maxHistory (${n}). Retained ${n} steps from position ${p}. Position adjusted to ${f}.`),{patches:y,position:f,metadata:r.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 h?e:new h(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=>u(t)),inversePatches:t.inversePatches[i].map(t=>u(t)),metadata:v(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=y(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=y(this.allMetadata.slice(-this.maxHistory))}}resetHistoryToCurrentState(){this.initialState=g(this.state),this.initialPosition=0,this.initialPatches=void 0,this.initialMetadata=void 0,this.position=0,this.allPatches=d(),this.allMetadata=[],this.tempPatches=d(),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&&c(this.state)&&c(t)){const[,s]=e.create(this.state,e=>{for(const t of Object.keys(e))delete e[t];f(t,e),Array.isArray(e)&&Array.isArray(t)&&(e.length=t.length)},this.options);return void e.apply(this.state,s,{mutable:!0})}this.state=t}captureTransactionSnapshot(){return{state:this.mutable&&c(this.state)?g(this.state):this.state,position:this.position,allPatches:d(this.allPatches),allMetadata:y(this.allMetadata),tempPatches:d(this.tempPatches),tempMetadata:v(this.tempMetadata),initialState:g(this.initialState),initialPosition:this.initialPosition,initialPatches:this.initialPatches?d(this.initialPatches):void 0,initialMetadata:this.initialMetadata?y(this.initialMetadata):void 0,pendingState:this.pendingState,pendingStateVersion:this.pendingStateVersion}}restoreTransactionSnapshot(t){this.restoreStateFromSnapshot(t.state),this.position=t.position,this.allPatches=d(t.allPatches),this.allMetadata=y(t.allMetadata),this.tempPatches=d(t.tempPatches),this.tempMetadata=v(t.tempMetadata),this.initialState=g(t.initialState),this.initialPosition=t.initialPosition,this.initialPatches=t.initialPatches?d(t.initialPatches):void 0,this.initialMetadata=t.initialMetadata?y(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,s){let i,a,r;const n=this.mutable&&c(this.state),o="function"==typeof t,h=Array.isArray(this.state),p=Array.isArray(t),u=!h&&!p&&l(this.state)&&l(t),d=h&&p&&b(this.state)&&b(t),y=o&&n||n&&!o&&(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.")),y){const[s,n,h]=e.create(this.state,o?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);i=n,a=h,this.hasRootReplacement(i)?("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=s,r=s):(e.apply(this.state,i,{mutable:!0}),r=this.state)}else{const[s,n,o]=e.create(this.state,"function"==typeof t?s=>{const i=t(s);return i===s?i:c(i)&&!P(i)?e.rawReturn(i):i}:()=>c(t)?e.rawReturn(t):t,this.options);i=n,a=o,this.state=s,r=s}if(0===i.length&&0===a.length)return;this.pendingState=r;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",s);if(this.autoArchive)this.position<this.allPatches.patches.length&&this.discardFutureFrom(this.position),this.allPatches.patches.push(i),this.allPatches.inversePatches.push(a),this.allMetadata.push(v(s)),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(i),this.tempPatches.inversePatches.push(a),void 0===s&&void 0!==this.tempMetadata||(this.tempMetadata=v(s))}this.invalidateHistoryCache(),this.emitChange("setState",s)}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(v(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:v(t),i="function"==typeof t?t:e;if(!i)return;const a=this.autoArchive,r=this.transactionMetadata,n=0===this.transactionDepth,o=this.captureTransactionSnapshot();let h=!1;this.transactionDepth+=1,(n||!this.transactionMetadata&&s)&&(this.transactionMetadata=s),this.autoArchive=!1;try{i()}catch(t){throw h=!0,this.restoreTransactionSnapshot(o),this.transactionMetadata=r,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=r)}}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 s=null!==(t=this.pendingState)&&void 0!==t?t:this.state,i=e.apply(s,this.tempPatches.inversePatches.flat().reverse()),[,a,r]=e.create(s,()=>c(i)?e.rawReturn(i):i,this.options);return{patches:r,inversePatches:a}}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 s=this.getAllPatches(),i=!this.autoArchive&&s.patches.length>this.maxHistory?s.patches.slice(s.patches.length-this.maxHistory):s.patches,a=!this.autoArchive&&s.inversePatches.length>this.maxHistory?s.inversePatches.slice(s.inversePatches.length-this.maxHistory):s.inversePatches,r=[];for(let s=this.position;s<i.length;s++)t=e.apply(t,i[s]),r.push(t);t=this.state;const n=[];for(let s=this.position-1;s>-1;s--)t=e.apply(t,a[s]),n.push(t);n.reverse();const o=[...n,this.state,...r];return this.historyCache={version:this.historyVersion,history:o},"production"!==process.env.NODE_ENV&&Object.freeze(o),o}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 s=!this.autoArchive&&!!this.tempPatches.patches.length;s&&this.archive();const i=this.getAllPatches(),a=t<this.position;if(t>i.patches.length&&(console.warn(`Can't go forward to position ${t}`),t=i.patches.length),t<0&&(console.warn(`Can't go back to position ${t}`),t=0),t===this.position)return;const r=s&&i.inversePatches.length>0?i.inversePatches.map((t,e,s)=>e===s.length-1?[...t].reverse():t):i.inversePatches,n=a?r.slice(-this.maxHistory).slice(t,this.position).flat().reverse():i.patches.slice(-this.maxHistory).slice(this.position,t).flat();this.mutable&&c(this.state)&&!this.hasRootReplacement(n)?e.apply(this.state,n,{mutable:!0}):this.state=e.apply(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&&c(this.state)&&c(this.initialState)){const[,t]=e.create(this.state,t=>{for(const e of Object.keys(t))delete t[e];f(this.initialState,t),Array.isArray(t)&&Array.isArray(this.initialState)&&(t.length=this.initialState.length)},this.options);e.apply(this.state,t,{mutable:!0})}else this.state=g(this.initialState);this.position=this.initialPosition,this.allPatches=d(this.initialPatches),this.allMetadata=this.initialMetadata?y(this.initialMetadata):[],this.tempPatches=d(),this.tempMetadata=void 0,this.invalidateHistoryCache(),this.emitChange("reset")}rebase(){this.initialState=g(this.state),this.initialPosition=0,this.initialPatches=void 0,this.initialMetadata=void 0,this.position=0,this.allPatches=d(),this.allMetadata=[],this.tempPatches=d(),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 d(t)}serialize(){return{version:1,state:g(this.state),patches:this.getPatches(),position:this.getPosition(),metadata:this.getMetadata()}}getMetadata(){const t=m(this.allMetadata,this.allPatches.patches.length);return!this.autoArchive&&this.tempPatches.patches.length&&t.push(v(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 A,O={exports:{}},w={};var M,T,_={};
/**
* @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 N=(T||(T=1,"production"===process.env.NODE_ENV?O.exports=function(){if(A)return w;A=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,r=e.useLayoutEffect,n=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 r(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]),n(s),s};return w.useSyncExternalStore=void 0!==e.useSyncExternalStore?e.useSyncExternalStore:h,w}():O.exports=(M||(M=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,r=s.useEffect,n=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 n(function(){d.value=p,d.getSnapshot=l,e(d)&&v({inst:d})},[t,p,l]),r(function(){return e(d)&&v({inst:d}),t(function(){e(d)&&v({inst:d})})},[t]),o(p),p};_.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())}()),_)),O.exports);exports.useTravel=function(e,s={}){const i=t.useRef(null);i.current||(i.current=new E(e,Object.assign(Object.assign({},s),{mutable:!1})));const[,a]=t.useReducer(t=>t+1,0),r=t.useRef(!1);t.useEffect(()=>{r.current=!1}),t.useEffect(()=>i.current.subscribe(()=>{a()}),[]);const n=i.current,o=t.useCallback(t=>{if(r.current)throw new Error("setState cannot be called multiple times in the same render cycle.");r.current=!0,n.setState(t)},[n]);return[n.getState(),o,t.useMemo(()=>{const t=n.getControls();return{get position(){return n.getPosition()},getHistory:()=>t.getHistory(),get patches(){return n.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():n.archive()},canArchive:()=>"canArchive"in t?t.canArchive():n.canArchive()}},[n])]},exports.useTravelStore=function(e){if(Boolean(null==e?void 0:e.mutable))throw new Error("useTravelStore only supports immutable Travels instances. Remove `mutable: true` or use useTravel instead.");return[N.useSyncExternalStore(e.subscribe,e.getState,e.getState),t.useCallback(t=>e.setState(t),[e]),t.useMemo(()=>{const t=e.getControls();return Object.defineProperties({},Object.assign(Object.assign({},Object.getOwnPropertyDescriptors(t)),{canUndo:{get:()=>t.canBack(),enumerable:!0},canRedo:{get:()=>t.canForward(),enumerable:!0}}))},[e])]};
//# sourceMappingURL=index.cjs.js.map