@@ -15,36 +15,38 @@ export const temporalStateCreator = <TState>(
1515 futureStates : options ?. futureStates || [ ] ,
1616 undo : ( steps = 1 ) => {
1717 if ( get ( ) . pastStates . length ) {
18- // Fastest way to clone an array on Chromium. Needed to create a new array reference
19- const pastStates = get ( ) . pastStates . slice ( ) ;
20- const futureStates = get ( ) . futureStates . slice ( ) ;
21- // While loop is fastest in Chromium.
22- // Based on the steps, get values from the pastStates array and push them to the futureStates array
23- while ( steps -- ) {
24- const pastState = pastStates . pop ( ) ;
25- if ( pastState ) {
26- futureStates . push ( options ?. partialize ?.( userGet ( ) ) || userGet ( ) ) ;
27- userSet ( pastState ) ;
28- }
29- }
30- set ( { pastStates, futureStates } ) ;
18+ // userGet must be called before userSet
19+ const currentState = options ?. partialize ?.( userGet ( ) ) || userGet ( ) ;
20+
21+ const statesToApply = get ( ) . pastStates . splice ( - steps , steps ) ;
22+
23+ // If there is length, we know that statesToApply is not empty
24+ userSet ( statesToApply . shift ( ) ! ) ;
25+ set ( {
26+ pastStates : get ( ) . pastStates ,
27+ futureStates : get ( ) . futureStates . concat (
28+ currentState ,
29+ statesToApply . reverse ( ) ,
30+ ) ,
31+ } ) ;
3132 }
3233 } ,
3334 redo : ( steps = 1 ) => {
3435 if ( get ( ) . futureStates . length ) {
35- // Fastest way to clone an array on Chromium. Needed to create a new array reference
36- const pastStates = get ( ) . pastStates . slice ( ) ;
37- const futureStates = get ( ) . futureStates . slice ( ) ;
38- // While loop is fastest in Chromium.
39- // Based on the steps, get values from the futureStates array and push them to the pastStates array
40- while ( steps -- ) {
41- const futureState = futureStates . pop ( ) ;
42- if ( futureState ) {
43- pastStates . push ( options ?. partialize ?.( userGet ( ) ) || userGet ( ) ) ;
44- userSet ( futureState ) ;
45- }
46- }
47- set ( { pastStates, futureStates } ) ;
36+ // userGet must be called before userSet
37+ const currentState = options ?. partialize ?.( userGet ( ) ) || userGet ( ) ;
38+
39+ const statesToApply = get ( ) . futureStates . splice ( - steps , steps ) ;
40+
41+ // If there is length, we know that statesToApply is not empty
42+ userSet ( statesToApply . shift ( ) ! ) ;
43+ set ( {
44+ pastStates : get ( ) . pastStates . concat (
45+ currentState ,
46+ statesToApply . reverse ( ) ,
47+ ) ,
48+ futureStates : get ( ) . futureStates ,
49+ } ) ;
4850 }
4951 } ,
5052 clear : ( ) => set ( { pastStates : [ ] , futureStates : [ ] } ) ,
@@ -58,14 +60,16 @@ export const temporalStateCreator = <TState>(
5860 if ( get ( ) . isTracking ) {
5961 const currentState = options ?. partialize ?.( userGet ( ) ) || userGet ( ) ;
6062 if ( ! options ?. equality ?.( pastState , currentState ) ) {
61- const pastStates = get ( ) . pastStates . slice ( ) ;
6263 // This naively assumes that only one new state can be added at a time
63- if ( options ?. limit && pastStates . length >= options ?. limit ) {
64- pastStates . shift ( ) ;
64+ if ( options ?. limit && get ( ) . pastStates . length >= options ?. limit ) {
65+ get ( ) . pastStates . shift ( ) ;
6566 }
66- pastStates . push ( pastState ) ;
67+
6768 get ( ) . _onSave ?.( pastState , currentState ) ;
68- set ( { pastStates, futureStates : [ ] } ) ;
69+ set ( {
70+ pastStates : get ( ) . pastStates . concat ( pastState ) ,
71+ futureStates : [ ] ,
72+ } ) ;
6973 }
7074 }
7175 } ,
0 commit comments