Skip to content

Commit cc4d0ce

Browse files
committed
Add typescript, vite and vitest
1 parent dd7f91f commit cc4d0ce

23 files changed

+1981
-3471
lines changed

babel.config.json

Lines changed: 0 additions & 10 deletions
This file was deleted.

dist/bundle.js

Lines changed: 317 additions & 1939 deletions
Large diffs are not rendered by default.

dist/index.d.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
import { default as Undo } from './undo';
2+
export { type UndoConfig, type UndoConstructor, type UndoSettings } from './undo';
3+
export * from './observer';
4+
export * from './types';
5+
export default Undo;

dist/observer.d.ts

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
/**
2+
* @typedef {Object} Observer
3+
* @description Custom MutationObserver to detect changes in the editor.
4+
* @property {String} holder — Editor.js holder id.
5+
* @property {Object} observer - MutationObserver object that detects changes in the editor.
6+
* @property {Number} debounceTimer - Delay time for the debouncer.
7+
* @property {Function} mutationDebouncer - Debouncer to delay the changes registration.
8+
*/
9+
export default class Observer {
10+
private debounceTimer;
11+
private holder;
12+
private mutationDebouncer;
13+
private observer;
14+
/**
15+
* Creates a new instance of the Observer object.
16+
* @param {Function} registerChange - Function that register a change in the history stack.
17+
* @param {String} holder - Editor.js holder id.
18+
* @param {Number} debounceTimer Delay time for the debouncer.
19+
*/
20+
constructor(registerChange: () => void, holder: Element, debounceTimer: number);
21+
/**
22+
* Sets a mutation observer to catch every change in the editor.
23+
*/
24+
setMutationObserver(): void;
25+
/**
26+
* Handles the mutations and checks if a new mutation has been produced.
27+
* @param {Object} mutationList The registered mutations
28+
*/
29+
mutationHandler(mutationList: MutationRecord[]): void;
30+
/**
31+
* Delays invoking a function until after wait millis have elapsed.
32+
* @param {Function} callback The function to be delayed.
33+
* @param {Number} wait The deplay time in millis.
34+
*/
35+
debounce(callback: (...args: unknown[]) => void, wait: number): (...args: unknown[]) => void;
36+
onDestroy(): void;
37+
}

dist/types.d.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
import { default as EditorJS, EditorConfig } from '@editorjs/editorjs';
2+
export interface EditorJsReady extends EditorJS {
3+
configuration: EditorConfig;
4+
}

dist/undo.d.ts

Lines changed: 165 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,165 @@
1+
import { default as EditorJS, OutputBlockData, OutputData } from '@editorjs/editorjs';
2+
import { EditorJsReady } from './types';
3+
import { Blocks, Caret } from '@editorjs/editorjs/types/api';
4+
export type UndoConfig = {
5+
debounceTimer: number;
6+
shortcuts: {
7+
redo: string[];
8+
undo: string[];
9+
};
10+
};
11+
export type UndoSettings = {
12+
debounceTimer?: number;
13+
shortcuts?: {
14+
redo?: string[] | string;
15+
undo?: string[] | string;
16+
};
17+
};
18+
interface StackStated {
19+
caretIndex?: null | number;
20+
index: number;
21+
state: OutputBlockData[];
22+
}
23+
export type UndoConstructor = {
24+
config?: UndoSettings;
25+
maxLength?: number;
26+
onUpdate?: () => void;
27+
editor: EditorJS;
28+
};
29+
/**
30+
* Undo/Redo feature for Editor.js.
31+
*
32+
* @typedef {Object} Undo
33+
* @description Feature's initialization class.
34+
* @property {Object} editor — Editor.js instance object.
35+
* @property {Number} maxLength - Max amount of changes recorded by the history stack.
36+
* @property {Function} onUpdate - Callback called when the user performs an undo or redo action.
37+
* @property {Boolean} shouldSaveHistory - Defines if the plugin should save the change in the stack
38+
* @property {Object} initialItem - Initial data object.
39+
*/
40+
export default class Undo {
41+
blocks: Blocks;
42+
caret: Caret;
43+
config: UndoConfig;
44+
defaultBlock: string | undefined;
45+
editor: EditorJsReady;
46+
holder: HTMLElement | null | undefined;
47+
initialItem: null | StackStated;
48+
maxLength: number;
49+
onUpdate: () => void;
50+
position: number;
51+
readOnly: boolean | undefined;
52+
shouldSaveHistory: boolean;
53+
stack: StackStated[];
54+
/**
55+
* @param options — Plugin custom options.
56+
*/
57+
constructor({ editor, config, onUpdate, maxLength }: UndoConstructor);
58+
/**
59+
* Notify core that read-only mode is suppoorted
60+
*
61+
* @returns {boolean}
62+
*/
63+
static get isReadOnlySupported(): boolean;
64+
/**
65+
* Truncates the history stack when it excedes the limit of changes.
66+
*
67+
* @param {Object} stack Changes history stack.
68+
* @param {Number} stack Limit of changes recorded by the history stack.
69+
*/
70+
truncate(stack: StackStated[], limit: number): void;
71+
/**
72+
* Initializes the stack when the user provides initial data.
73+
*
74+
* @param {Object} initialItem Initial data provided by the user.
75+
*/
76+
initialize(initialItem: OutputData | OutputBlockData[]): void;
77+
/**
78+
* Clears the history stack.
79+
*/
80+
clear(): void;
81+
/**
82+
* Returns true if readOnly was toggled to true
83+
* @returns {Node} Indirectly shows if readOnly was set to true or false
84+
*/
85+
setReadOnly(): void;
86+
/**
87+
* Registers the data returned by API's save method into the history stack.
88+
*/
89+
registerChange(): void;
90+
/**
91+
* Checks if the saved data has to be added to the history stack.
92+
*
93+
* @param {Object} newData New data to be saved in the history stack.
94+
* @returns {Boolean}
95+
*/
96+
editorDidUpdate(newData: OutputBlockData[]): boolean;
97+
/**
98+
* Adds the saved data in the history stack and updates current position.
99+
*/
100+
save(state: OutputBlockData[]): void;
101+
/**
102+
* Gets the caret position.
103+
* @param {Number} index is the block index
104+
* @returns The caret position
105+
*/
106+
getCaretIndex(index: number): number | null;
107+
/**
108+
* Decreases the current position and update the respective block in the editor.
109+
*/
110+
undo(): Promise<void>;
111+
/**
112+
* Sets the caret position.
113+
* @param {Number} index is the block index
114+
* @param {Number} caretIndex is the caret position
115+
* @param {Array} state is the current state according to this.position.
116+
*/
117+
setCaretIndex(index: number, caretIndex: number): void;
118+
/**
119+
* Inserts new block
120+
* @param {Array} state is the current state according to this.position.
121+
* @param {Number} index is the block index
122+
*/
123+
insertBlock(state: OutputBlockData[], index: number): void;
124+
/**
125+
* Updates the passed block or render the state when the content was copied.
126+
* @param {Array} state is the current state according to this.position.
127+
* @param {Number} index is the block index.
128+
*/
129+
updateModifiedBlock(state: OutputBlockData[], index: number): Promise<void | import('@editorjs/editorjs').BlockAPI>;
130+
/**
131+
* Increases the current position and update the respective block in the editor.
132+
*/
133+
redo(): Promise<void>;
134+
switchState(stateToApply: OutputBlockData[], stateToCompare: OutputBlockData[]): Promise<void>;
135+
/**
136+
* Checks if the history stack can perform an undo action.
137+
*
138+
* @returns {Boolean}
139+
*/
140+
canUndo(): boolean;
141+
/**
142+
* Checks if the history stack can perform a redo action.
143+
*
144+
* @returns {Boolean}
145+
*/
146+
canRedo(): boolean;
147+
/**
148+
* Returns the number of changes recorded in the history stack.
149+
*
150+
* @returns {Number}
151+
*/
152+
count(): number;
153+
/**
154+
* Parses the keys passed in the shortcut property to accept CMD,ALT and SHIFT
155+
*
156+
* @param {Array} keys are the keys passed in shortcuts in config
157+
* @returns {Array}
158+
*/
159+
parseKeys(keys: string[]): string[];
160+
/**
161+
* Sets events listeners to allow keyboard actions support
162+
*/
163+
setEventListeners(): void;
164+
}
165+
export {};

package.json

Lines changed: 18 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -9,15 +9,18 @@
99
],
1010
"description": "Undo tool for Editor.js",
1111
"main": "./dist/bundle.js",
12+
"types": "./dist/index.d.ts",
1213
"scripts": {
13-
"build": "webpack --mode production",
14-
"build:dev": "webpack --mode development --watch",
15-
"test": "jest"
14+
"build": "vite build --mode production",
15+
"build:dev": "vite",
16+
"test": "vitest run",
17+
"test:watch": "vitest"
1618
},
1719
"repository": {
1820
"type": "git",
1921
"url": "git+https://github.com/kommitters/editorjs-undo"
2022
},
23+
"type": "module",
2124
"author": {
2225
"name": "kommitters Open Source",
2326
"email": "oss@kommit.co"
@@ -28,28 +31,27 @@
2831
},
2932
"homepage": "https://github.com/kommitters/editorjs-undo#readme",
3033
"devDependencies": {
31-
"@babel/core": "^7.10.2",
32-
"@babel/plugin-transform-runtime": "^7.23.2",
33-
"@babel/preset-env": "^7.10.2",
34-
"babel-jest": "^29.0.0",
35-
"babel-loader": "^9.0.0",
34+
"@editorjs/editorjs": "^2.30.8",
35+
"@testing-library/dom": "^10.4.0",
36+
"@testing-library/jest-dom": "^6.6.3",
37+
"@types/deep-equal": "^1.0.4",
3638
"eslint": "^8.3.0",
3739
"eslint-config-airbnb-base": "^15.0.0",
3840
"eslint-plugin-import": "^2.25.2",
3941
"eslint-plugin-jest": "^27.0.0",
4042
"jest": "^29.0.0",
4143
"jest-environment-jsdom": "^29.3.1",
42-
"webpack": "^5.52.0",
43-
"webpack-cli": "^5.0.0"
44-
},
45-
"jest": {
46-
"transform": {
47-
"^.+\\.jsx?$": "babel-jest",
48-
"^.+\\.(css|svg)$": "<rootDir>/test/config/assetsTransform.js"
49-
}
44+
"rollup-plugin-node-externals": "^8.0.0",
45+
"typescript": "^5.7.3",
46+
"vite": "^6.1.0",
47+
"vite-plugin-dts": "^4.5.0",
48+
"vitest": "^3.0.5"
5049
},
5150
"dependencies": {
5251
"deep-equal": "^2.2.3",
5352
"vanilla-caret-js": "^1.0.1"
53+
},
54+
"peerDependencies": {
55+
"@editorjs/editorjs": ">=2"
5456
}
5557
}

src/index.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
import Undo from "./undo";
2+
export { type UndoConfig, type UndoConstructor, type UndoSettings } from "./undo";
3+
export * from "./observer";
4+
export * from "./types";
5+
6+
export default Undo;

src/observer.js renamed to src/observer.ts

Lines changed: 19 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -7,13 +7,18 @@
77
* @property {Function} mutationDebouncer - Debouncer to delay the changes registration.
88
*/
99
export default class Observer {
10+
private debounceTimer: number;
11+
private holder: Element;
12+
private mutationDebouncer: (...args: any[]) => void;
13+
private observer: MutationObserver | null;
14+
1015
/**
1116
* Creates a new instance of the Observer object.
1217
* @param {Function} registerChange - Function that register a change in the history stack.
1318
* @param {String} holder - Editor.js holder id.
1419
* @param {Number} debounceTimer Delay time for the debouncer.
1520
*/
16-
constructor(registerChange, holder, debounceTimer) {
21+
constructor(registerChange: () => void, holder: Element, debounceTimer: number) {
1722
this.holder = holder;
1823
this.observer = null;
1924
this.debounceTimer = debounceTimer;
@@ -39,14 +44,14 @@ export default class Observer {
3944
this.observer = new MutationObserver((mutationList) => {
4045
this.mutationHandler(mutationList);
4146
});
42-
this.observer.observe(target, observerOptions);
47+
this.observer.observe(target as Node, observerOptions);
4348
}
4449

4550
/**
4651
* Handles the mutations and checks if a new mutation has been produced.
4752
* @param {Object} mutationList The registered mutations
4853
*/
49-
mutationHandler(mutationList) {
54+
mutationHandler(mutationList: MutationRecord[]) {
5055
let contentMutated = false;
5156

5257
mutationList.forEach((mutation) => {
@@ -62,7 +67,11 @@ export default class Observer {
6267
contentMutated = true;
6368
break;
6469
case 'attributes':
65-
if (!mutation.target.classList.contains('ce-block') && !mutation.target.classList.contains('tc-toolbox')) {
70+
if (
71+
mutation.target instanceof Element &&
72+
!mutation.target.classList.contains('ce-block') &&
73+
!mutation.target.classList.contains('tc-toolbox')
74+
) {
6675
contentMutated = true;
6776
}
6877
break;
@@ -79,18 +88,18 @@ export default class Observer {
7988
* @param {Function} callback The function to be delayed.
8089
* @param {Number} wait The deplay time in millis.
8190
*/
82-
debounce(callback, wait) {
83-
let timeout;
84-
return (...args) => {
91+
debounce(callback: (...args: unknown[]) => void, wait: number) {
92+
let timeout: number;
93+
return (...args: unknown[]) => {
8594
const context = this;
86-
clearTimeout(timeout);
87-
timeout = setTimeout(() => callback.apply(context, args), wait);
95+
window.clearTimeout(timeout);
96+
timeout = window.setTimeout(() => callback.apply(context, args), wait);
8897
};
8998
}
9099

91100
onDestroy() {
92101
const destroyEvent = new CustomEvent('destroy');
93102
document.dispatchEvent(destroyEvent);
94-
this.observer.disconnect();
103+
this.observer != null && this.observer.disconnect();
95104
}
96105
}

src/types.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
import EditorJS from '@editorjs/editorjs';
2+
import { EditorConfig } from '@editorjs/editorjs';
3+
4+
export interface EditorJsReady extends EditorJS {
5+
configuration: EditorConfig;
6+
}

0 commit comments

Comments
 (0)