Skip to content

Commit

Permalink
feat(state-history): 🔥 Add an option to control future state (#475)
Browse files Browse the repository at this point in the history
An option called resetFutureOnNewState has been added to the
StateHistoryOptions interface. This option allows the user to control
whether the future redo states should be cleared when a new state is
added after the user has undone one or more state changes. The default
value of this option is set to false, meaning that by default, the
future states will not be cleared.
  • Loading branch information
johnfewell authored Aug 6, 2023
1 parent 8de9ffb commit 65738ad
Show file tree
Hide file tree
Showing 3 changed files with 58 additions and 1 deletion.
16 changes: 16 additions & 0 deletions docs/docs/features/history/history.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -133,3 +133,19 @@ An observable that returns whether you're not in the latest step in the history:
```ts
propsStateHistory.hasFuture$;
```

### `resetFutureOnNewState`

A boolean flag in the `StateHistoryOptions` that controls whether the future redo states should be cleared when a new state is added after the user has undone one or more state changes.

If `resetFutureOnNewState` is set to `true`, the future states will be cleared when a new state is added. If it's set to `false` (which is the defalt value), the future states will be preserved.

Here is how you can set `resetFutureOnNewState` when calling the `stateHistory` method:

```ts
const propsStateHistory = stateHistory(propsStore, {
resetFutureOnNewState: false,
});
```

In this example, the future states will not be cleared when a new state is added, allowing the user to still redo previously undone state changes even after a new state has been added.
29 changes: 29 additions & 0 deletions packages/state-history/src/lib/state-history.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -182,4 +182,33 @@ describe('state history', () => {

expect(history.getFuture()).toEqual([{ counter: 5, newProperty: false }]);
});

it('should clear the future state when adding new state after undo', () => {
const { state, config } = createState(withProp());
const store = new Store({ state, config, name: '' });

const history = stateHistory(store, { resetFutureOnNewState: true });

eq(store, 0);

store.update(setProp(1));
eq(store, 1);

history.undo();
eq(store, 0);

history.redo();
eq(store, 1);

history.undo();
eq(store, 0);

store.update(setProp(2));
eq(store, 2);

history.redo();
eq(store, 2);

expect(history.getFuture()).toEqual([]);
});
});
14 changes: 13 additions & 1 deletion packages/state-history/src/lib/state-history.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ export interface StateHistoryOptions<State> {

// comparatorFn: (prev, current) => isEqual(prev, current) === false
comparatorFn: (prevState: State, currentState: State) => boolean;
resetFutureOnNewState?: boolean;
}

type History<State> = {
Expand Down Expand Up @@ -41,7 +42,12 @@ export class StateHistory<T extends Store, State extends StoreValue<T>> {
protected store: T,
private options: Partial<StateHistoryOptions<State>> = {}
) {
this.mergedOptions = { maxAge: 10, comparatorFn: () => true, ...options };
this.mergedOptions = {
maxAge: 10,
comparatorFn: () => true,
resetFutureOnNewState: false,
...options,
};
this.activate();
}

Expand Down Expand Up @@ -78,6 +84,12 @@ export class StateHistory<T extends Store, State extends StoreValue<T>> {
this.history.past = [...this.history.past, past];
}
this.history.present = present;
if (
this.mergedOptions.resetFutureOnNewState &&
this.history.future.length > 0
) {
this.history.future = [];
}
this.updateHasHistory();
}
});
Expand Down

0 comments on commit 65738ad

Please sign in to comment.