UNPKG

use-travel

Version:

A React hook for state time travel with undo, redo, reset, rebase and archive functionalities.

12 lines (11 loc) 28.8 kB
!function(t,e){"object"==typeof exports&&"undefined"!=typeof module?e(exports,require("react"),require("mutative")):"function"==typeof define&&define.amd?define(["exports","react","mutative"],e):e((t="undefined"!=typeof globalThis?globalThis:t||self).UseTravel={},t.React,t.Mutative)}(this,function(t,e,s){"use strict";"function"==typeof SuppressedError&&SuppressedError;class i extends Error{constructor(t,e,s={}){super(e),this.name="TravelsPersistenceError",this.code=t,this.cause=s.cause}}const a=t=>"object"==typeof t&&null!==t,n=t=>null==t||a(t)&&!Array.isArray(t),r=t=>{if(!a(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},o=t=>Array.isArray(t)&&t.every(t=>Array.isArray(t)&&t.every(r)),h=t=>{if(!a(t))throw new i("INVALID_SCHEMA","Travels: persisted history must be an object.");if(1!==t.version)throw new i("UNSUPPORTED_VERSION",`Travels: unsupported persisted history version ${String(t.version)}. Expected 1.`);if(!("state"in t))throw new i("INVALID_SCHEMA","Travels: persisted history must include 'state'.");if(!("patches"in t))throw new i("INVALID_SCHEMA","Travels: persisted history must include 'patches'.");const e=t.patches,s=(t=>{if(!a(t))return"patches must be an object with 'patches' and 'inversePatches' arrays";const e=t;return o(e.patches)&&o(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 i("INVALID_PATCHES",`Travels: ${s}.`);const r=t.position;if("number"!=typeof r||!Number.isFinite(r)||!Number.isInteger(r)||r<0||e&&r>e.patches.length)throw new i("INVALID_SCHEMA",`Travels: persisted history position ${String(r)} is invalid for the patch history.`);const h=t.metadata;let c;if(void 0!==h){if(!Array.isArray(h))throw new i("INVALID_SCHEMA","Travels: persisted history 'metadata' must be an array when provided.");const t=h;if(!t.every(n))throw new i("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 i("INVALID_SCHEMA","Travels: persisted history 'metadata' length must match patches length.");return{version:1,state:t.state,patches:e,position:r,metadata:c}};class c extends Error{constructor(t,e,s={}){super(e),this.name="TravelsError",this.code=t,this.cause=s.cause}}const l=t=>"object"==typeof t&&null!==t,p=t=>{if(!l(t))return!1;const e=Object.getPrototypeOf(t);return null===e||e===Object.prototype},u=t=>{if("function"==typeof globalThis.structuredClone)try{return globalThis.structuredClone(t)}catch(t){return}},d=(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]=d(t[i],e));return s}if(t instanceof Map){const s=new Map;return e.set(t,s),t.forEach((t,i)=>{s.set(d(i,e),d(t,e))}),s}if(t instanceof Set){const s=new Set;return e.set(t,s),t.forEach(t=>{s.add(d(t,e))}),s}if(t instanceof Date){const s=new Date(t.getTime());return e.set(t,s),s}const s=u(t);if(void 0!==s)return e.set(t,s),s;if(!p(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]=d(t[s],e));return i},v=t=>({patches:t?t.patches.map(t=>t.map(t=>d(t))):[],inversePatches:t?t.inversePatches.map(t=>t.map(t=>d(t))):[]}),y=t=>t?d(t):void 0,m=t=>t.map(y),f=(t,e)=>Array.from({length:e},(e,s)=>y(null==t?void 0:t[s])),g=(t,e)=>{if(e&&t&&"object"==typeof t){for(const s in t)Object.prototype.hasOwnProperty.call(t,s)&&(e[s]=d(t[s]));return e}return d(t)},P=t=>{if(null===t||"object"!=typeof t)return t;const e=u(t);return void 0!==e?e:g(t)},b=(t,e=new WeakSet)=>{if(!l(t))return!1;if(s.isDraft(t))return!0;const i=t;if(e.has(i))return!1;if(e.add(i),t instanceof Map){for(const[s,i]of t)if(b(s,e)||b(i,e))return!0;return!1}if(t instanceof Set){for(const s of t)if(b(s,e))return!0;return!1}for(const t of Reflect.ownKeys(i))if(b(i[t],e))return!0;return!1},S=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),E=t=>Array.isArray(t)&&t.every(t=>Array.isArray(t));class A{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 i("PARSE_ERROR","Travels: persisted history is not valid JSON.",{cause:t})}})(t);let a=s;if(e.migrate)try{a=e.migrate(s)}catch(t){throw new i("MIGRATION_FAILED","Travels: persisted history migration failed.",{cause:t})}return h(a)}catch(t){const a=t instanceof i?t:new i("INVALID_SCHEMA","Travels: persisted history could not be deserialized.",{cause:t});null===(s=e.onError)||void 0===s||s.call(e,a);const n=(t=>{if(t)return"function"==typeof t?t():t})(e.fallback);if(n)return h(n);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: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: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 g=null!==(s=null==n?void 0:n.patches)&&void 0!==s?s:r,b=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 S=(t=>t?E(t.patches)&&E(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)(g);if(S){if(h)throw new Error(`Travels: ${S}`);"production"!==process.env.NODE_ENV&&console.warn(`Travels: ${S}. Falling back to empty history. Set strictInitialPatches: true to throw instead.`),g=void 0,b=0}this.state=t,this.initialState=P(t),this.maxHistory=a,this.autoArchive=c,this.mutable=l,this.warnOnUnsupportedState=p,this.onError=u,this.onBranchDiscard=d,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(g,b,null==n?void 0:n.metadata);this.allPatches=A,this.allMetadata=w,this.initialPatches=g?v(A):void 0,this.initialMetadata=(null==n?void 0:n.metadata)?w.slice():void 0,this.position=O,this.initialPosition=O,this.tempPatches=v(),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=v(t),a=i.patches.length,n=f(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:v(),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)},y=v(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:y,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 c?e:new c(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=>d(t)),inversePatches:t.inversePatches[i].map(t=>d(t)),metadata:y(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=m(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=m(this.allMetadata.slice(-this.maxHistory))}}resetHistoryToCurrentState(){this.initialState=P(this.state),this.initialPosition=0,this.initialPatches=void 0,this.initialMetadata=void 0,this.position=0,this.allPatches=v(),this.allMetadata=[],this.tempPatches=v(),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&&l(this.state)&&l(t)){const[,e]=s.create(this.state,e=>{for(const t of Object.keys(e))delete e[t];g(t,e),Array.isArray(e)&&Array.isArray(t)&&(e.length=t.length)},this.options);return void s.apply(this.state,e,{mutable:!0})}this.state=t}captureTransactionSnapshot(){return{state:this.mutable&&l(this.state)?P(this.state):this.state,position:this.position,allPatches:v(this.allPatches),allMetadata:m(this.allMetadata),tempPatches:v(this.tempPatches),tempMetadata:y(this.tempMetadata),initialState:P(this.initialState),initialPosition:this.initialPosition,initialPatches:this.initialPatches?v(this.initialPatches):void 0,initialMetadata:this.initialMetadata?m(this.initialMetadata):void 0,pendingState:this.pendingState,pendingStateVersion:this.pendingStateVersion}}restoreTransactionSnapshot(t){this.restoreStateFromSnapshot(t.state),this.position=t.position,this.allPatches=v(t.allPatches),this.allMetadata=m(t.allMetadata),this.tempPatches=v(t.tempPatches),this.tempMetadata=y(t.tempMetadata),this.initialState=P(t.initialState),this.initialPosition=t.initialPosition,this.initialPatches=t.initialPatches?v(t.initialPatches):void 0,this.initialMetadata=t.initialMetadata?m(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 i,a,n;const r=this.mutable&&l(this.state),o="function"==typeof t,h=Array.isArray(this.state),c=Array.isArray(t),u=!h&&!c&&p(this.state)&&p(t),d=h&&c&&S(this.state)&&S(t),v=o&&r||r&&!o&&(d||u);if(!this.mutable||r||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,r,h]=s.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=r,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=e,n=e):(s.apply(this.state,i,{mutable:!0}),n=this.state)}else{const[e,r,o]=s.create(this.state,"function"==typeof t?e=>{const i=t(e);return i===e?i:l(i)&&!b(i)?s.rawReturn(i):i}:()=>l(t)?s.rawReturn(t):t,this.options);i=r,a=o,this.state=e,n=e}if(0===i.length&&0===a.length)return;this.pendingState=n;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(i),this.allPatches.inversePatches.push(a),this.allMetadata.push(y(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(i),this.tempPatches.inversePatches.push(a),void 0===e&&void 0!==this.tempMetadata||(this.tempMetadata=y(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(y(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:y(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,i=s.apply(e,this.tempPatches.inversePatches.flat().reverse()),[,a,n]=s.create(e,()=>l(i)?s.rawReturn(i):i,this.options);return{patches:n,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 e=this.getAllPatches(),i=!this.autoArchive&&e.patches.length>this.maxHistory?e.patches.slice(e.patches.length-this.maxHistory):e.patches,a=!this.autoArchive&&e.inversePatches.length>this.maxHistory?e.inversePatches.slice(e.inversePatches.length-this.maxHistory):e.inversePatches,n=[];for(let e=this.position;e<i.length;e++)t=s.apply(t,i[e]),n.push(t);t=this.state;const r=[];for(let e=this.position-1;e>-1;e--)t=s.apply(t,a[e]),r.push(t);r.reverse();const o=[...r,this.state,...n];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 e=!this.autoArchive&&!!this.tempPatches.patches.length;e&&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 n=e&&i.inversePatches.length>0?i.inversePatches.map((t,e,s)=>e===s.length-1?[...t].reverse():t):i.inversePatches,r=a?n.slice(-this.maxHistory).slice(t,this.position).flat().reverse():i.patches.slice(-this.maxHistory).slice(this.position,t).flat();this.mutable&&l(this.state)&&!this.hasRootReplacement(r)?s.apply(this.state,r,{mutable:!0}):this.state=s.apply(this.state,r),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&&l(this.state)&&l(this.initialState)){const[,t]=s.create(this.state,t=>{for(const e of Object.keys(t))delete t[e];g(this.initialState,t),Array.isArray(t)&&Array.isArray(this.initialState)&&(t.length=this.initialState.length)},this.options);s.apply(this.state,t,{mutable:!0})}else this.state=P(this.initialState);this.position=this.initialPosition,this.allPatches=v(this.initialPatches),this.allMetadata=this.initialMetadata?m(this.initialMetadata):[],this.tempPatches=v(),this.tempMetadata=void 0,this.invalidateHistoryCache(),this.emitChange("reset")}rebase(){this.initialState=P(this.state),this.initialPosition=0,this.initialPatches=void 0,this.initialMetadata=void 0,this.position=0,this.allPatches=v(),this.allMetadata=[],this.tempPatches=v(),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 v(t)}serialize(){return{version:1,state:P(this.state),patches:this.getPatches(),position:this.getPosition(),metadata:this.getMetadata()}}getMetadata(){const t=f(this.allMetadata,this.allPatches.patches.length);return!this.autoArchive&&this.tempPatches.patches.length&&t.push(y(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 O,w={exports:{}},M={};var T,_,N={}; /** * @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 C=(_||(_=1,"production"===process.env.NODE_ENV?w.exports=function(){if(O)return M;O=1;var t=e,s="function"==typeof Object.is?Object.is:function(t,e){return t===e&&(0!==t||1/t==1/e)||t!=t&&e!=e},i=t.useState,a=t.useEffect,n=t.useLayoutEffect,r=t.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 M.useSyncExternalStore=void 0!==t.useSyncExternalStore?t.useSyncExternalStore:h,M}():w.exports=(T||(T=1,"production"!==process.env.NODE_ENV&&function(){function t(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=e,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(e,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,t(d)&&v({inst:d})},[e,p,l]),n(function(){return t(d)&&v({inst:d}),e(function(){t(d)&&v({inst:d})})},[e]),o(p),p};N.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())}()),N)),w.exports);t.useTravel=function(t,s={}){const i=e.useRef(null);i.current||(i.current=new A(t,Object.assign(Object.assign({},s),{mutable:!1})));const[,a]=e.useReducer(t=>t+1,0),n=e.useRef(!1);e.useEffect(()=>{n.current=!1}),e.useEffect(()=>i.current.subscribe(()=>{a()}),[]);const r=i.current,o=e.useCallback(t=>{if(n.current)throw new Error("setState cannot be called multiple times in the same render cycle.");n.current=!0,r.setState(t)},[r]);return[r.getState(),o,e.useMemo(()=>{const t=r.getControls();return{get position(){return r.getPosition()},getHistory:()=>t.getHistory(),get patches(){return r.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():r.archive()},canArchive:()=>"canArchive"in t?t.canArchive():r.canArchive()}},[r])]},t.useTravelStore=function(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[C.useSyncExternalStore(t.subscribe,t.getState,t.getState),e.useCallback(e=>t.setState(e),[t]),e.useMemo(()=>{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])]}}); //# sourceMappingURL=index.umd.js.map