Skip to content

Commit 452c28f

Browse files
dhruvikpatel18dhruvikpatel18manzoorwanijk
authored
Migrate undo-manager package to TS (#70757)
Co-authored-by: dhruvikpatel18 <[email protected]> Co-authored-by: manzoorwanijk <[email protected]>
1 parent b860887 commit 452c28f

File tree

4 files changed

+119
-60
lines changed

4 files changed

+119
-60
lines changed

packages/compose/src/hooks/use-state-with-history/index.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ import { useCallback, useReducer } from '@wordpress/element';
66
import type { UndoManager } from '@wordpress/undo-manager';
77

88
type UndoRedoState< T > = {
9-
manager: UndoManager;
9+
manager: UndoManager< T >;
1010
value: T;
1111
};
1212

packages/undo-manager/README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ Creates an undo manager.
2020

2121
_Returns_
2222

23-
- `UndoManager`: Undo manager.
23+
- `UndoManager< T >`: Undo manager.
2424

2525
<!-- END TOKEN(Autogenerated API docs) -->
2626

packages/undo-manager/src/index.js renamed to packages/undo-manager/src/index.ts

Lines changed: 57 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -3,24 +3,49 @@
33
*/
44
import isShallowEqual from '@wordpress/is-shallow-equal';
55

6-
/** @typedef {import('./types').HistoryRecord} HistoryRecord */
7-
/** @typedef {import('./types').HistoryChange} HistoryChange */
8-
/** @typedef {import('./types').HistoryChanges} HistoryChanges */
9-
/** @typedef {import('./types').UndoManager} UndoManager */
6+
/**
7+
* Internal dependencies
8+
*/
9+
import type {
10+
HistoryChange as _HistoryChange,
11+
HistoryChanges as _HistoryChanges,
12+
HistoryRecord as _HistoryRecord,
13+
UndoManager as _UndoManager,
14+
} from './types';
15+
16+
/**
17+
* Represents a single change in history.
18+
*/
19+
export type HistoryChange< T = unknown > = _HistoryChange< T >;
20+
21+
/**
22+
* Represents changes for a single item.
23+
*/
24+
export type HistoryChanges< T = unknown > = _HistoryChanges< T >;
25+
26+
/**
27+
* Represents a record of history changes.
28+
*/
29+
export type HistoryRecord< T = unknown > = _HistoryRecord< T >;
30+
31+
/**
32+
* The undo manager interface.
33+
*/
34+
export type UndoManager< T = unknown > = _UndoManager< T >;
1035

1136
/**
1237
* Merge changes for a single item into a record of changes.
1338
*
14-
* @param {Record< string, HistoryChange >} changes1 Previous changes
15-
* @param {Record< string, HistoryChange >} changes2 NextChanges
39+
* @param changes1 Previous changes
40+
* @param changes2 Next changes
1641
*
17-
* @return {Record< string, HistoryChange >} Merged changes
42+
* @return Merged changes
1843
*/
19-
function mergeHistoryChanges( changes1, changes2 ) {
20-
/**
21-
* @type {Record< string, HistoryChange >}
22-
*/
23-
const newChanges = { ...changes1 };
44+
function mergeHistoryChanges< T >(
45+
changes1: Record< string, HistoryChange< T > >,
46+
changes2: Record< string, HistoryChange< T > >
47+
): Record< string, HistoryChange< T > > {
48+
const newChanges: Record< string, HistoryChange< T > > = { ...changes1 };
2449
Object.entries( changes2 ).forEach( ( [ key, value ] ) => {
2550
if ( newChanges[ key ] ) {
2651
newChanges[ key ] = { ...newChanges[ key ], to: value.to };
@@ -35,10 +60,13 @@ function mergeHistoryChanges( changes1, changes2 ) {
3560
/**
3661
* Adds history changes for a single item into a record of changes.
3762
*
38-
* @param {HistoryRecord} record The record to merge into.
39-
* @param {HistoryChanges} changes The changes to merge.
63+
* @param record The record to merge into.
64+
* @param changes The changes to merge.
4065
*/
41-
const addHistoryChangesIntoRecord = ( record, changes ) => {
66+
const addHistoryChangesIntoRecord = < T >(
67+
record: HistoryRecord< T >,
68+
changes: HistoryChanges< T >
69+
): HistoryRecord< T > => {
4270
const existingChangesIndex = record?.findIndex(
4371
( { id: recordIdentifier } ) => {
4472
return typeof recordIdentifier === 'string'
@@ -66,28 +94,19 @@ const addHistoryChangesIntoRecord = ( record, changes ) => {
6694
/**
6795
* Creates an undo manager.
6896
*
69-
* @return {UndoManager} Undo manager.
97+
* @return Undo manager.
7098
*/
71-
export function createUndoManager() {
72-
/**
73-
* @type {HistoryRecord[]}
74-
*/
75-
let history = [];
76-
/**
77-
* @type {HistoryRecord}
78-
*/
79-
let stagedRecord = [];
80-
/**
81-
* @type {number}
82-
*/
99+
export function createUndoManager< T = unknown >(): UndoManager< T > {
100+
let history: HistoryRecord< T >[] = [];
101+
let stagedRecord: HistoryRecord< T > = [];
83102
let offset = 0;
84103

85-
const dropPendingRedos = () => {
104+
const dropPendingRedos = (): void => {
86105
history = history.slice( 0, offset || undefined );
87106
offset = 0;
88107
};
89108

90-
const appendStagedRecordToLatestHistoryRecord = () => {
109+
const appendStagedRecordToLatestHistoryRecord = (): void => {
91110
const index = history.length === 0 ? 0 : history.length - 1;
92111
let latestRecord = history[ index ] ?? [];
93112
stagedRecord.forEach( ( changes ) => {
@@ -102,10 +121,10 @@ export function createUndoManager() {
102121
* A record is considered empty if it the changes keep the same values.
103122
* Also updates to function values are ignored.
104123
*
105-
* @param {HistoryRecord} record
106-
* @return {boolean} Whether the record is empty.
124+
* @param record The record to check.
125+
* @return Whether the record is empty.
107126
*/
108-
const isRecordEmpty = ( record ) => {
127+
const isRecordEmpty = ( record: HistoryRecord< T > ): boolean => {
109128
const filteredRecord = record.filter( ( { changes } ) => {
110129
return Object.values( changes ).some(
111130
( { from, to } ) =>
@@ -118,13 +137,7 @@ export function createUndoManager() {
118137
};
119138

120139
return {
121-
/**
122-
* Record changes into the history.
123-
*
124-
* @param {HistoryRecord=} record A record of changes to record.
125-
* @param {boolean} isStaged Whether to immediately create an undo point or not.
126-
*/
127-
addRecord( record, isStaged = false ) {
140+
addRecord( record?: HistoryRecord< T >, isStaged = false ): void {
128141
const isEmpty = ! record || isRecordEmpty( record );
129142
if ( isStaged ) {
130143
if ( isEmpty ) {
@@ -148,7 +161,7 @@ export function createUndoManager() {
148161
}
149162
},
150163

151-
undo() {
164+
undo(): HistoryRecord< T > | undefined {
152165
if ( stagedRecord.length ) {
153166
dropPendingRedos();
154167
appendStagedRecordToLatestHistoryRecord();
@@ -161,7 +174,7 @@ export function createUndoManager() {
161174
return undoRecord;
162175
},
163176

164-
redo() {
177+
redo(): HistoryRecord< T > | undefined {
165178
const redoRecord = history[ history.length + offset ];
166179
if ( ! redoRecord ) {
167180
return;
@@ -170,11 +183,11 @@ export function createUndoManager() {
170183
return redoRecord;
171184
},
172185

173-
hasUndo() {
186+
hasUndo(): boolean {
174187
return !! history[ history.length - 1 + offset ];
175188
},
176189

177-
hasRedo() {
190+
hasRedo(): boolean {
178191
return !! history[ history.length + offset ];
179192
},
180193
};

packages/undo-manager/src/types.ts

Lines changed: 60 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,65 @@
1-
export type HistoryChange = {
2-
from: any;
3-
to: any;
4-
};
1+
/**
2+
* Represents a single change in history.
3+
*/
4+
export interface HistoryChange< From = unknown, To = From > {
5+
/** The previous value */
6+
from: From;
7+
/** The new value */
8+
to: To;
9+
}
510

6-
export type HistoryChanges = {
7-
id: string | Record< string, any >;
8-
changes: Record< string, HistoryChange >;
9-
};
11+
/**
12+
* Represents changes for a single item.
13+
*/
14+
export interface HistoryChanges< T = unknown > {
15+
/** The identifier for the item being changed */
16+
id: string | Record< string, unknown >;
17+
/** The changes made to the item */
18+
changes: Record< string, HistoryChange< T > >;
19+
}
1020

11-
export type HistoryRecord = Array< HistoryChanges >;
21+
/**
22+
* Represents a record of history changes.
23+
*/
24+
export type HistoryRecord< T = unknown > = HistoryChanges< T >[];
1225

13-
export type UndoManager = {
14-
addRecord: ( record: HistoryRecord, isStaged: boolean ) => void;
15-
undo: () => HistoryRecord | undefined;
16-
redo: () => HistoryRecord | undefined;
26+
/**
27+
* The undo manager interface.
28+
*/
29+
export interface UndoManager< T = unknown > {
30+
/**
31+
* Record changes into the history.
32+
*
33+
* @param record A record of changes to record.
34+
* @param isStaged Whether to immediately create an undo point or not.
35+
*/
36+
addRecord: ( record?: HistoryRecord< T >, isStaged?: boolean ) => void;
37+
38+
/**
39+
* Undo the last recorded changes.
40+
*
41+
* @return The undone record or undefined if nothing to undo.
42+
*/
43+
undo: () => HistoryRecord< T > | undefined;
44+
45+
/**
46+
* Redo the last undone changes.
47+
*
48+
* @return The redone record or undefined if nothing to redo.
49+
*/
50+
redo: () => HistoryRecord< T > | undefined;
51+
52+
/**
53+
* Check if there are changes that can be undone.
54+
*
55+
* @return Whether there are changes to undo.
56+
*/
1757
hasUndo: () => boolean;
58+
59+
/**
60+
* Check if there are changes that can be redone.
61+
*
62+
* @return Whether there are changes to redo.
63+
*/
1864
hasRedo: () => boolean;
19-
};
65+
}

0 commit comments

Comments
 (0)