@pixerate/editor 0.7.0 → 0.8.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/history/index.cjs +260 -0
- package/dist/history/index.cjs.map +1 -0
- package/dist/history/index.d.cts +109 -0
- package/dist/history/index.d.ts +109 -0
- package/dist/history/index.js +232 -0
- package/dist/history/index.js.map +1 -0
- package/dist/index.cjs +232 -0
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +1 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +230 -0
- package/dist/index.js.map +1 -1
- package/package.json +6 -1
package/dist/index.d.cts
CHANGED
|
@@ -6,6 +6,7 @@ export { ExtractedMention, escapeHtml, extractMentionsFromDoc, getEditorMarkdown
|
|
|
6
6
|
import { Editor, EditorOptions, Content, Extensions } from '@tiptap/core';
|
|
7
7
|
export { Content, Editor, EditorOptions, Extensions } from '@tiptap/core';
|
|
8
8
|
export { ASTNode, BinaryOpNode, CellCoordinate, CellData, CellDep, CellFormat, CellRange, CellRefNode, ColumnBinding, ColumnType, DataSourceBinder, DependencyGraph, EvaluationContext, FormulaEvaluator, FormulaParser, FormulaToken, FormulaTokenType, FunctionCallNode, LiteralNode, PropertyRefNode, RangeNode, RowType, SpreadsheetColumn, SpreadsheetController, SpreadsheetControllerOptions, SpreadsheetDataSource, SpreadsheetDataSourceField, SpreadsheetDocument, SpreadsheetRow, UnaryOpNode, colNameToIndex, extractCellDependencies, indexToColName, parseCellReference, parseFormula, parseRange, tokenizeFormula } from './spreadsheet/index.cjs';
|
|
9
|
+
export { Command, HistoryManager, HistoryManagerOptions, HistoryState, MergedExecutionOptions, SnapshotCommandOptions, createHistoryManager } from './history/index.cjs';
|
|
9
10
|
export { MarkdownOptions } from 'tiptap-markdown';
|
|
10
11
|
import '@tiptap/pm/view';
|
|
11
12
|
import '@tiptap/pm/model';
|
package/dist/index.d.ts
CHANGED
|
@@ -6,6 +6,7 @@ export { ExtractedMention, escapeHtml, extractMentionsFromDoc, getEditorMarkdown
|
|
|
6
6
|
import { Editor, EditorOptions, Content, Extensions } from '@tiptap/core';
|
|
7
7
|
export { Content, Editor, EditorOptions, Extensions } from '@tiptap/core';
|
|
8
8
|
export { ASTNode, BinaryOpNode, CellCoordinate, CellData, CellDep, CellFormat, CellRange, CellRefNode, ColumnBinding, ColumnType, DataSourceBinder, DependencyGraph, EvaluationContext, FormulaEvaluator, FormulaParser, FormulaToken, FormulaTokenType, FunctionCallNode, LiteralNode, PropertyRefNode, RangeNode, RowType, SpreadsheetColumn, SpreadsheetController, SpreadsheetControllerOptions, SpreadsheetDataSource, SpreadsheetDataSourceField, SpreadsheetDocument, SpreadsheetRow, UnaryOpNode, colNameToIndex, extractCellDependencies, indexToColName, parseCellReference, parseFormula, parseRange, tokenizeFormula } from './spreadsheet/index.js';
|
|
9
|
+
export { Command, HistoryManager, HistoryManagerOptions, HistoryState, MergedExecutionOptions, SnapshotCommandOptions, createHistoryManager } from './history/index.js';
|
|
9
10
|
export { MarkdownOptions } from 'tiptap-markdown';
|
|
10
11
|
import '@tiptap/pm/view';
|
|
11
12
|
import '@tiptap/pm/model';
|
package/dist/index.js
CHANGED
|
@@ -3834,6 +3834,234 @@ var DirtyTracker = class {
|
|
|
3834
3834
|
function createDirtyTracker(initialBaseline, options) {
|
|
3835
3835
|
return new DirtyTracker(initialBaseline, options);
|
|
3836
3836
|
}
|
|
3837
|
+
|
|
3838
|
+
// src/history/HistoryManager.ts
|
|
3839
|
+
var HistoryManager = class {
|
|
3840
|
+
undoStack = [];
|
|
3841
|
+
redoStack = [];
|
|
3842
|
+
maxDepth;
|
|
3843
|
+
isApplying = false;
|
|
3844
|
+
batchDepth = 0;
|
|
3845
|
+
currentBatch = null;
|
|
3846
|
+
listeners = /* @__PURE__ */ new Set();
|
|
3847
|
+
onStateChange;
|
|
3848
|
+
cachedState;
|
|
3849
|
+
constructor(options = {}) {
|
|
3850
|
+
this.maxDepth = options.maxDepth ?? 50;
|
|
3851
|
+
this.onStateChange = options.onStateChange;
|
|
3852
|
+
this.cachedState = this.computeState();
|
|
3853
|
+
}
|
|
3854
|
+
computeState() {
|
|
3855
|
+
const canUndo = this.undoStack.length > 0;
|
|
3856
|
+
const canRedo = this.redoStack.length > 0;
|
|
3857
|
+
return {
|
|
3858
|
+
canUndo,
|
|
3859
|
+
canRedo,
|
|
3860
|
+
undoName: canUndo ? this.undoStack[this.undoStack.length - 1].name : "",
|
|
3861
|
+
redoName: canRedo ? this.redoStack[this.redoStack.length - 1].name : "",
|
|
3862
|
+
undoCount: this.undoStack.length,
|
|
3863
|
+
redoCount: this.redoStack.length
|
|
3864
|
+
};
|
|
3865
|
+
}
|
|
3866
|
+
/**
|
|
3867
|
+
* Returns a snapshot of the current history state.
|
|
3868
|
+
* Cached to maintain referential equality across renders for useSyncExternalStore.
|
|
3869
|
+
*/
|
|
3870
|
+
getState() {
|
|
3871
|
+
return this.cachedState;
|
|
3872
|
+
}
|
|
3873
|
+
notify() {
|
|
3874
|
+
this.cachedState = this.computeState();
|
|
3875
|
+
const state = this.cachedState;
|
|
3876
|
+
this.onStateChange?.(state);
|
|
3877
|
+
this.listeners.forEach((listener) => {
|
|
3878
|
+
try {
|
|
3879
|
+
listener(state);
|
|
3880
|
+
} catch (err) {
|
|
3881
|
+
console.error("[HistoryManager] Error in state listener:", err);
|
|
3882
|
+
}
|
|
3883
|
+
});
|
|
3884
|
+
}
|
|
3885
|
+
/**
|
|
3886
|
+
* Executes a command and pushes it onto the undo stack.
|
|
3887
|
+
* Clears the redo stack.
|
|
3888
|
+
*/
|
|
3889
|
+
execute(command) {
|
|
3890
|
+
if (this.isApplying) {
|
|
3891
|
+
command.execute();
|
|
3892
|
+
return;
|
|
3893
|
+
}
|
|
3894
|
+
if (this.batchDepth > 0 && this.currentBatch) {
|
|
3895
|
+
command.execute();
|
|
3896
|
+
this.currentBatch.push({
|
|
3897
|
+
...command,
|
|
3898
|
+
timestamp: command.timestamp ?? Date.now()
|
|
3899
|
+
});
|
|
3900
|
+
return;
|
|
3901
|
+
}
|
|
3902
|
+
command.execute();
|
|
3903
|
+
this.undoStack.push({
|
|
3904
|
+
...command,
|
|
3905
|
+
timestamp: command.timestamp ?? Date.now()
|
|
3906
|
+
});
|
|
3907
|
+
if (this.undoStack.length > this.maxDepth) {
|
|
3908
|
+
this.undoStack.shift();
|
|
3909
|
+
}
|
|
3910
|
+
this.redoStack = [];
|
|
3911
|
+
this.notify();
|
|
3912
|
+
}
|
|
3913
|
+
/**
|
|
3914
|
+
* Executes a command, coalescing it with the previous command if they share
|
|
3915
|
+
* the same `tag` and occurred within `windowMs` (default: 300ms).
|
|
3916
|
+
* Useful for high-frequency interactions like slider scrubs or node drags.
|
|
3917
|
+
*/
|
|
3918
|
+
executeMerged(command, options = {}) {
|
|
3919
|
+
const windowMs = options.windowMs ?? 300;
|
|
3920
|
+
const now = Date.now();
|
|
3921
|
+
if (command.tag && this.undoStack.length > 0 && this.batchDepth === 0 && !this.isApplying) {
|
|
3922
|
+
const top = this.undoStack[this.undoStack.length - 1];
|
|
3923
|
+
const elapsed = top.timestamp ? now - top.timestamp : Infinity;
|
|
3924
|
+
if (top.tag === command.tag && elapsed <= windowMs) {
|
|
3925
|
+
command.execute();
|
|
3926
|
+
const initialUndo = top.undo;
|
|
3927
|
+
this.undoStack[this.undoStack.length - 1] = {
|
|
3928
|
+
name: command.name,
|
|
3929
|
+
tag: command.tag,
|
|
3930
|
+
timestamp: now,
|
|
3931
|
+
execute: command.execute,
|
|
3932
|
+
undo: initialUndo,
|
|
3933
|
+
redo: command.redo ?? command.execute
|
|
3934
|
+
};
|
|
3935
|
+
this.redoStack = [];
|
|
3936
|
+
this.notify();
|
|
3937
|
+
return;
|
|
3938
|
+
}
|
|
3939
|
+
}
|
|
3940
|
+
this.execute({ ...command, timestamp: now });
|
|
3941
|
+
}
|
|
3942
|
+
/**
|
|
3943
|
+
* Batches multiple commands executed within `fn` into a single atomic undo entry.
|
|
3944
|
+
*/
|
|
3945
|
+
batch(name, fn) {
|
|
3946
|
+
if (this.isApplying) {
|
|
3947
|
+
fn();
|
|
3948
|
+
return;
|
|
3949
|
+
}
|
|
3950
|
+
if (this.batchDepth > 0) {
|
|
3951
|
+
fn();
|
|
3952
|
+
return;
|
|
3953
|
+
}
|
|
3954
|
+
this.batchDepth++;
|
|
3955
|
+
this.currentBatch = [];
|
|
3956
|
+
try {
|
|
3957
|
+
fn();
|
|
3958
|
+
} finally {
|
|
3959
|
+
this.batchDepth--;
|
|
3960
|
+
const batchCommands = this.currentBatch;
|
|
3961
|
+
this.currentBatch = null;
|
|
3962
|
+
if (batchCommands && batchCommands.length > 0) {
|
|
3963
|
+
const compoundCommand = {
|
|
3964
|
+
name,
|
|
3965
|
+
timestamp: Date.now(),
|
|
3966
|
+
execute: () => {
|
|
3967
|
+
for (let i = 0; i < batchCommands.length; i++) {
|
|
3968
|
+
(batchCommands[i].redo ?? batchCommands[i].execute)();
|
|
3969
|
+
}
|
|
3970
|
+
},
|
|
3971
|
+
undo: () => {
|
|
3972
|
+
for (let i = batchCommands.length - 1; i >= 0; i--) {
|
|
3973
|
+
batchCommands[i].undo();
|
|
3974
|
+
}
|
|
3975
|
+
},
|
|
3976
|
+
redo: () => {
|
|
3977
|
+
for (let i = 0; i < batchCommands.length; i++) {
|
|
3978
|
+
(batchCommands[i].redo ?? batchCommands[i].execute)();
|
|
3979
|
+
}
|
|
3980
|
+
}
|
|
3981
|
+
};
|
|
3982
|
+
this.undoStack.push(compoundCommand);
|
|
3983
|
+
if (this.undoStack.length > this.maxDepth) {
|
|
3984
|
+
this.undoStack.shift();
|
|
3985
|
+
}
|
|
3986
|
+
this.redoStack = [];
|
|
3987
|
+
this.notify();
|
|
3988
|
+
}
|
|
3989
|
+
}
|
|
3990
|
+
}
|
|
3991
|
+
/**
|
|
3992
|
+
* Reverts the most recent command on the undo stack.
|
|
3993
|
+
* Returns true if a command was undone, false otherwise.
|
|
3994
|
+
*/
|
|
3995
|
+
undo() {
|
|
3996
|
+
if (this.undoStack.length === 0 || this.isApplying || this.batchDepth > 0) {
|
|
3997
|
+
return false;
|
|
3998
|
+
}
|
|
3999
|
+
this.isApplying = true;
|
|
4000
|
+
try {
|
|
4001
|
+
const command = this.undoStack.pop();
|
|
4002
|
+
command.undo();
|
|
4003
|
+
this.redoStack.push(command);
|
|
4004
|
+
return true;
|
|
4005
|
+
} finally {
|
|
4006
|
+
this.isApplying = false;
|
|
4007
|
+
this.notify();
|
|
4008
|
+
}
|
|
4009
|
+
}
|
|
4010
|
+
/**
|
|
4011
|
+
* Re-applies the most recent undone command on the redo stack.
|
|
4012
|
+
* Returns true if a command was redone, false otherwise.
|
|
4013
|
+
*/
|
|
4014
|
+
redo() {
|
|
4015
|
+
if (this.redoStack.length === 0 || this.isApplying || this.batchDepth > 0) {
|
|
4016
|
+
return false;
|
|
4017
|
+
}
|
|
4018
|
+
this.isApplying = true;
|
|
4019
|
+
try {
|
|
4020
|
+
const command = this.redoStack.pop();
|
|
4021
|
+
(command.redo ?? command.execute)();
|
|
4022
|
+
this.undoStack.push(command);
|
|
4023
|
+
return true;
|
|
4024
|
+
} finally {
|
|
4025
|
+
this.isApplying = false;
|
|
4026
|
+
this.notify();
|
|
4027
|
+
}
|
|
4028
|
+
}
|
|
4029
|
+
/**
|
|
4030
|
+
* Clears both undo and redo stacks.
|
|
4031
|
+
*/
|
|
4032
|
+
clear() {
|
|
4033
|
+
this.undoStack = [];
|
|
4034
|
+
this.redoStack = [];
|
|
4035
|
+
this.notify();
|
|
4036
|
+
}
|
|
4037
|
+
/**
|
|
4038
|
+
* Subscribes to history state changes.
|
|
4039
|
+
* The listener is immediately invoked with the current state.
|
|
4040
|
+
* Returns an unsubscribe function.
|
|
4041
|
+
*/
|
|
4042
|
+
subscribe(listener) {
|
|
4043
|
+
this.listeners.add(listener);
|
|
4044
|
+
listener(this.getState());
|
|
4045
|
+
return () => {
|
|
4046
|
+
this.listeners.delete(listener);
|
|
4047
|
+
};
|
|
4048
|
+
}
|
|
4049
|
+
/**
|
|
4050
|
+
* Utility helper to create a Command from before/after state snapshots.
|
|
4051
|
+
*/
|
|
4052
|
+
static createSnapshotCommand(options) {
|
|
4053
|
+
return {
|
|
4054
|
+
name: options.name,
|
|
4055
|
+
tag: options.tag,
|
|
4056
|
+
execute: () => options.apply(options.after),
|
|
4057
|
+
undo: () => options.apply(options.before),
|
|
4058
|
+
redo: () => options.apply(options.after)
|
|
4059
|
+
};
|
|
4060
|
+
}
|
|
4061
|
+
};
|
|
4062
|
+
function createHistoryManager(options = {}) {
|
|
4063
|
+
return new HistoryManager(options);
|
|
4064
|
+
}
|
|
3837
4065
|
export {
|
|
3838
4066
|
ColorHighlighter,
|
|
3839
4067
|
DataSourceBinder,
|
|
@@ -3844,6 +4072,7 @@ export {
|
|
|
3844
4072
|
FormulaEvaluator,
|
|
3845
4073
|
FormulaParser,
|
|
3846
4074
|
GradientText,
|
|
4075
|
+
HistoryManager,
|
|
3847
4076
|
INSTRUCTION_REGEX,
|
|
3848
4077
|
Image2 as Image,
|
|
3849
4078
|
LoadingNode,
|
|
@@ -3858,6 +4087,7 @@ export {
|
|
|
3858
4087
|
colNameToIndex,
|
|
3859
4088
|
createDirtyTracker,
|
|
3860
4089
|
createEditor,
|
|
4090
|
+
createHistoryManager,
|
|
3861
4091
|
createMentionExtension,
|
|
3862
4092
|
createRichTextPreset,
|
|
3863
4093
|
defaultIsEqual,
|