@flowgram.ai/free-history-plugin 0.5.1 → 0.5.3
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/esm/index.js +37 -190
- package/dist/esm/index.js.map +1 -1
- package/dist/index.d.mts +1 -5
- package/dist/index.d.ts +1 -5
- package/dist/index.js +54 -207
- package/dist/index.js.map +1 -1
- package/package.json +9 -9
package/dist/esm/index.js
CHANGED
|
@@ -10,8 +10,8 @@ var __decorateClass = (decorators, target, key, kind) => {
|
|
|
10
10
|
};
|
|
11
11
|
|
|
12
12
|
// src/create-free-history-plugin.ts
|
|
13
|
-
import { bindContributions, definePluginCreator } from "@flowgram.ai/core";
|
|
14
13
|
import { HistoryContainerModule, OperationContribution } from "@flowgram.ai/history";
|
|
14
|
+
import { bindContributions, definePluginCreator } from "@flowgram.ai/core";
|
|
15
15
|
|
|
16
16
|
// src/history-entity-manager.ts
|
|
17
17
|
import { cloneDeep, isEqual } from "lodash-es";
|
|
@@ -104,12 +104,12 @@ DragNodesHandler = __decorateClass([
|
|
|
104
104
|
injectable2()
|
|
105
105
|
], DragNodesHandler);
|
|
106
106
|
|
|
107
|
-
// src/handlers/change-
|
|
108
|
-
import { cloneDeep as cloneDeep2, get, isEqual as isEqual2, set } from "lodash-es";
|
|
107
|
+
// src/handlers/change-content-handler.ts
|
|
109
108
|
import { injectable as injectable4, inject as inject2 } from "inversify";
|
|
110
109
|
import { HistoryService as HistoryService2 } from "@flowgram.ai/history";
|
|
111
|
-
import {
|
|
112
|
-
|
|
110
|
+
import {
|
|
111
|
+
WorkflowContentChangeType as WorkflowContentChangeType6
|
|
112
|
+
} from "@flowgram.ai/free-layout-core";
|
|
113
113
|
|
|
114
114
|
// src/free-history-config.ts
|
|
115
115
|
import { injectable as injectable3 } from "inversify";
|
|
@@ -157,72 +157,6 @@ FreeHistoryConfig = __decorateClass([
|
|
|
157
157
|
injectable3()
|
|
158
158
|
], FreeHistoryConfig);
|
|
159
159
|
|
|
160
|
-
// src/handlers/change-node-data-handler.ts
|
|
161
|
-
var ChangeNodeDataHandler = class {
|
|
162
|
-
handle(event) {
|
|
163
|
-
const { path, value, initialized, node } = event;
|
|
164
|
-
const formData = node.getData(FlowNodeFormData);
|
|
165
|
-
const oldValue = this._entityManager.getValue(formData);
|
|
166
|
-
const propPath = path.split("/").filter(Boolean).join(".");
|
|
167
|
-
const propOldValue = propPath ? get(oldValue, propPath) : oldValue;
|
|
168
|
-
if (isEqual2(value, propOldValue)) {
|
|
169
|
-
return;
|
|
170
|
-
}
|
|
171
|
-
if (initialized) {
|
|
172
|
-
let operationPath = path;
|
|
173
|
-
let operationValue = cloneDeep2(value);
|
|
174
|
-
let operationOldValue = propOldValue;
|
|
175
|
-
if (path !== "/") {
|
|
176
|
-
const clonedOldValue = cloneDeep2(oldValue);
|
|
177
|
-
set(clonedOldValue, propPath, value);
|
|
178
|
-
operationPath = path.split("/").filter(Boolean)[0];
|
|
179
|
-
operationValue = get(clonedOldValue, operationPath);
|
|
180
|
-
operationOldValue = get(oldValue, operationPath);
|
|
181
|
-
}
|
|
182
|
-
this._historyService.pushOperation(
|
|
183
|
-
{
|
|
184
|
-
type: "changeNodeData" /* changeNodeData */,
|
|
185
|
-
value: {
|
|
186
|
-
id: node.id,
|
|
187
|
-
path: operationPath,
|
|
188
|
-
value: operationValue,
|
|
189
|
-
oldValue: operationOldValue
|
|
190
|
-
},
|
|
191
|
-
uri: this._config.getNodeURI(node.id)
|
|
192
|
-
},
|
|
193
|
-
{ noApply: true }
|
|
194
|
-
);
|
|
195
|
-
}
|
|
196
|
-
if (propPath) {
|
|
197
|
-
set(oldValue, propPath, cloneDeep2(value));
|
|
198
|
-
} else {
|
|
199
|
-
this._entityManager.setValue(formData, cloneDeep2(value));
|
|
200
|
-
}
|
|
201
|
-
}
|
|
202
|
-
};
|
|
203
|
-
__decorateClass([
|
|
204
|
-
inject2(HistoryService2)
|
|
205
|
-
], ChangeNodeDataHandler.prototype, "_historyService", 2);
|
|
206
|
-
__decorateClass([
|
|
207
|
-
inject2(WorkflowDocument)
|
|
208
|
-
], ChangeNodeDataHandler.prototype, "document", 2);
|
|
209
|
-
__decorateClass([
|
|
210
|
-
inject2(HistoryEntityManager)
|
|
211
|
-
], ChangeNodeDataHandler.prototype, "_entityManager", 2);
|
|
212
|
-
__decorateClass([
|
|
213
|
-
inject2(FreeHistoryConfig)
|
|
214
|
-
], ChangeNodeDataHandler.prototype, "_config", 2);
|
|
215
|
-
ChangeNodeDataHandler = __decorateClass([
|
|
216
|
-
injectable4()
|
|
217
|
-
], ChangeNodeDataHandler);
|
|
218
|
-
|
|
219
|
-
// src/handlers/change-content-handler.ts
|
|
220
|
-
import { injectable as injectable5, inject as inject3 } from "inversify";
|
|
221
|
-
import { HistoryService as HistoryService3 } from "@flowgram.ai/history";
|
|
222
|
-
import {
|
|
223
|
-
WorkflowContentChangeType as WorkflowContentChangeType6
|
|
224
|
-
} from "@flowgram.ai/free-layout-core";
|
|
225
|
-
|
|
226
160
|
// src/changes/delete-node-change.ts
|
|
227
161
|
import { WorkflowContentChangeType } from "@flowgram.ai/free-layout-core";
|
|
228
162
|
var deleteNodeChange = {
|
|
@@ -287,13 +221,13 @@ var changeLineData = {
|
|
|
287
221
|
};
|
|
288
222
|
|
|
289
223
|
// src/changes/add-node-change.ts
|
|
290
|
-
import { WorkflowDocument
|
|
224
|
+
import { WorkflowDocument } from "@flowgram.ai/free-layout-core";
|
|
291
225
|
import { WorkflowContentChangeType as WorkflowContentChangeType4 } from "@flowgram.ai/free-layout-core";
|
|
292
226
|
var addNodeChange = {
|
|
293
227
|
type: WorkflowContentChangeType4.ADD_NODE,
|
|
294
228
|
toOperation: (event, ctx) => {
|
|
295
229
|
const config = ctx.get(FreeHistoryConfig);
|
|
296
|
-
const document = ctx.get(
|
|
230
|
+
const document = ctx.get(WorkflowDocument);
|
|
297
231
|
const node = event.entity;
|
|
298
232
|
const parentID = node.parent?.id;
|
|
299
233
|
const json = document.toNodeJSON(node);
|
|
@@ -355,17 +289,17 @@ var ChangeContentHandler = class {
|
|
|
355
289
|
}
|
|
356
290
|
};
|
|
357
291
|
__decorateClass([
|
|
358
|
-
|
|
292
|
+
inject2(HistoryService2)
|
|
359
293
|
], ChangeContentHandler.prototype, "_historyService", 2);
|
|
360
294
|
__decorateClass([
|
|
361
|
-
|
|
295
|
+
inject2(FreeHistoryConfig)
|
|
362
296
|
], ChangeContentHandler.prototype, "_historyConfig", 2);
|
|
363
297
|
ChangeContentHandler = __decorateClass([
|
|
364
|
-
|
|
298
|
+
injectable4()
|
|
365
299
|
], ChangeContentHandler);
|
|
366
300
|
|
|
367
301
|
// src/free-history-registers.ts
|
|
368
|
-
import { injectable as
|
|
302
|
+
import { injectable as injectable5 } from "inversify";
|
|
369
303
|
|
|
370
304
|
// src/operation-metas/reset-layout.ts
|
|
371
305
|
import { WorkflowResetLayoutService } from "@flowgram.ai/free-layout-core";
|
|
@@ -406,7 +340,7 @@ var resetLayoutOperationMeta = {
|
|
|
406
340
|
};
|
|
407
341
|
|
|
408
342
|
// src/operation-metas/move-child-nodes.ts
|
|
409
|
-
import { WorkflowDocument as
|
|
343
|
+
import { WorkflowDocument as WorkflowDocument2 } from "@flowgram.ai/free-layout-core";
|
|
410
344
|
import { OperationType } from "@flowgram.ai/document";
|
|
411
345
|
import { FlowNodeBaseType } from "@flowgram.ai/document";
|
|
412
346
|
import { TransformData as TransformData2 } from "@flowgram.ai/core";
|
|
@@ -424,7 +358,7 @@ var moveChildNodesOperationMeta = {
|
|
|
424
358
|
}
|
|
425
359
|
}),
|
|
426
360
|
apply: (operation, ctx) => {
|
|
427
|
-
const document = ctx.get(
|
|
361
|
+
const document = ctx.get(WorkflowDocument2);
|
|
428
362
|
document.moveChildNodes(operation.value);
|
|
429
363
|
const fromContainer = document.getNode(operation.value.fromParentId);
|
|
430
364
|
requestAnimationFrame(() => {
|
|
@@ -437,7 +371,7 @@ var moveChildNodesOperationMeta = {
|
|
|
437
371
|
};
|
|
438
372
|
|
|
439
373
|
// src/operation-metas/drag-nodes.ts
|
|
440
|
-
import { WorkflowDocument as
|
|
374
|
+
import { WorkflowDocument as WorkflowDocument3 } from "@flowgram.ai/free-layout-core";
|
|
441
375
|
import { TransformData as TransformData3 } from "@flowgram.ai/core";
|
|
442
376
|
var dragNodesOperationMeta = {
|
|
443
377
|
...baseOperationMeta,
|
|
@@ -452,7 +386,7 @@ var dragNodesOperationMeta = {
|
|
|
452
386
|
}),
|
|
453
387
|
apply: (operation, ctx) => {
|
|
454
388
|
operation.value.ids.forEach((id, index) => {
|
|
455
|
-
const document = ctx.get(
|
|
389
|
+
const document = ctx.get(WorkflowDocument3);
|
|
456
390
|
const node = document.getNode(id);
|
|
457
391
|
if (!node) {
|
|
458
392
|
return;
|
|
@@ -471,7 +405,7 @@ var dragNodesOperationMeta = {
|
|
|
471
405
|
};
|
|
472
406
|
|
|
473
407
|
// src/operation-metas/delete-node.ts
|
|
474
|
-
import { WorkflowDocument as
|
|
408
|
+
import { WorkflowDocument as WorkflowDocument4 } from "@flowgram.ai/free-layout-core";
|
|
475
409
|
var deleteNodeOperationMeta = {
|
|
476
410
|
...baseOperationMeta,
|
|
477
411
|
type: "deleteNode" /* deleteNode */,
|
|
@@ -480,7 +414,7 @@ var deleteNodeOperationMeta = {
|
|
|
480
414
|
type: "addNode" /* addNode */
|
|
481
415
|
}),
|
|
482
416
|
apply: (operation, ctx) => {
|
|
483
|
-
const document = ctx.get(
|
|
417
|
+
const document = ctx.get(WorkflowDocument4);
|
|
484
418
|
const node = document.getNode(operation.value.node.id);
|
|
485
419
|
if (node) {
|
|
486
420
|
node.dispose();
|
|
@@ -501,7 +435,7 @@ var deleteNodeOperationMeta = {
|
|
|
501
435
|
};
|
|
502
436
|
|
|
503
437
|
// src/operation-metas/delete-line.ts
|
|
504
|
-
import { WorkflowDocument as
|
|
438
|
+
import { WorkflowDocument as WorkflowDocument5 } from "@flowgram.ai/free-layout-core";
|
|
505
439
|
var deleteLineOperationMeta = {
|
|
506
440
|
...baseOperationMeta,
|
|
507
441
|
type: "deleteLine" /* deleteLine */,
|
|
@@ -510,7 +444,7 @@ var deleteLineOperationMeta = {
|
|
|
510
444
|
type: "addLine" /* addLine */
|
|
511
445
|
}),
|
|
512
446
|
apply: (operation, ctx) => {
|
|
513
|
-
const document = ctx.get(
|
|
447
|
+
const document = ctx.get(WorkflowDocument5);
|
|
514
448
|
document.removeNode(operation.value.id);
|
|
515
449
|
},
|
|
516
450
|
getLabel: (op, ctx) => "Delete Line",
|
|
@@ -526,66 +460,6 @@ var deleteLineOperationMeta = {
|
|
|
526
460
|
}
|
|
527
461
|
};
|
|
528
462
|
|
|
529
|
-
// src/operation-metas/change-node-data.ts
|
|
530
|
-
import { FlowNodeFormData as FlowNodeFormData2 } from "@flowgram.ai/form-core";
|
|
531
|
-
import { WorkflowDocument as WorkflowDocument7 } from "@flowgram.ai/free-layout-core";
|
|
532
|
-
var changeNodeDataOperationMeta = {
|
|
533
|
-
...baseOperationMeta,
|
|
534
|
-
type: "changeNodeData" /* changeNodeData */,
|
|
535
|
-
inverse: (op) => ({
|
|
536
|
-
...op,
|
|
537
|
-
value: {
|
|
538
|
-
...op.value,
|
|
539
|
-
value: op.value.oldValue,
|
|
540
|
-
oldValue: op.value.value
|
|
541
|
-
}
|
|
542
|
-
}),
|
|
543
|
-
apply: (operation, ctx) => {
|
|
544
|
-
const document = ctx.get(WorkflowDocument7);
|
|
545
|
-
const node = document.getNode(operation.value.id);
|
|
546
|
-
if (!node) {
|
|
547
|
-
return;
|
|
548
|
-
}
|
|
549
|
-
const formData = node.getData(FlowNodeFormData2);
|
|
550
|
-
if (!formData) {
|
|
551
|
-
return;
|
|
552
|
-
}
|
|
553
|
-
let { path } = operation.value;
|
|
554
|
-
if (path.endsWith("/") && path !== "/") {
|
|
555
|
-
path = path.slice(0, -1);
|
|
556
|
-
}
|
|
557
|
-
if (!path.startsWith("/")) {
|
|
558
|
-
path = `/${path}`;
|
|
559
|
-
}
|
|
560
|
-
const formItem = formData.formModel.getFormItemByPath(path);
|
|
561
|
-
if (!formItem) {
|
|
562
|
-
return;
|
|
563
|
-
}
|
|
564
|
-
formItem.value = operation.value.value;
|
|
565
|
-
},
|
|
566
|
-
shouldMerge: (op, prev, element) => {
|
|
567
|
-
if (!prev) {
|
|
568
|
-
return false;
|
|
569
|
-
}
|
|
570
|
-
if (Date.now() - element.getTimestamp() < 500) {
|
|
571
|
-
if (op.type === prev.type && // 相同类型
|
|
572
|
-
op.value.id === prev.value.id && // 相同节点
|
|
573
|
-
op.value?.path === prev.value?.path) {
|
|
574
|
-
return {
|
|
575
|
-
type: op.type,
|
|
576
|
-
value: {
|
|
577
|
-
...op.value,
|
|
578
|
-
value: op.value.value,
|
|
579
|
-
oldValue: prev.value.oldValue
|
|
580
|
-
}
|
|
581
|
-
};
|
|
582
|
-
}
|
|
583
|
-
return true;
|
|
584
|
-
}
|
|
585
|
-
return false;
|
|
586
|
-
}
|
|
587
|
-
};
|
|
588
|
-
|
|
589
463
|
// src/operation-metas/change-line-data.ts
|
|
590
464
|
import { WorkflowLinesManager } from "@flowgram.ai/free-layout-core";
|
|
591
465
|
var changeLineDataOperationMeta = {
|
|
@@ -630,8 +504,8 @@ var changeLineDataOperationMeta = {
|
|
|
630
504
|
};
|
|
631
505
|
|
|
632
506
|
// src/operation-metas/add-node.ts
|
|
633
|
-
import { cloneDeep as
|
|
634
|
-
import { WorkflowDocument as
|
|
507
|
+
import { cloneDeep as cloneDeep2 } from "lodash-es";
|
|
508
|
+
import { WorkflowDocument as WorkflowDocument6 } from "@flowgram.ai/free-layout-core";
|
|
635
509
|
var addNodeOperationMeta = {
|
|
636
510
|
...baseOperationMeta,
|
|
637
511
|
type: "addNode" /* addNode */,
|
|
@@ -640,9 +514,9 @@ var addNodeOperationMeta = {
|
|
|
640
514
|
type: "deleteNode" /* deleteNode */
|
|
641
515
|
}),
|
|
642
516
|
apply: async (operation, ctx) => {
|
|
643
|
-
const document = ctx.get(
|
|
517
|
+
const document = ctx.get(WorkflowDocument6);
|
|
644
518
|
await document.createWorkflowNode(
|
|
645
|
-
|
|
519
|
+
cloneDeep2(operation.value.node),
|
|
646
520
|
false,
|
|
647
521
|
operation.value.parentID
|
|
648
522
|
);
|
|
@@ -696,7 +570,6 @@ var operationMetas = [
|
|
|
696
570
|
deleteLineOperationMeta,
|
|
697
571
|
addNodeOperationMeta,
|
|
698
572
|
deleteNodeOperationMeta,
|
|
699
|
-
changeNodeDataOperationMeta,
|
|
700
573
|
resetLayoutOperationMeta,
|
|
701
574
|
dragNodesOperationMeta,
|
|
702
575
|
moveChildNodesOperationMeta,
|
|
@@ -712,22 +585,19 @@ var FreeHistoryRegisters = class {
|
|
|
712
585
|
}
|
|
713
586
|
};
|
|
714
587
|
FreeHistoryRegisters = __decorateClass([
|
|
715
|
-
|
|
588
|
+
injectable5()
|
|
716
589
|
], FreeHistoryRegisters);
|
|
717
590
|
|
|
718
591
|
// src/free-history-manager.ts
|
|
719
|
-
import {
|
|
720
|
-
import {
|
|
721
|
-
import {
|
|
722
|
-
import { HistoryService as HistoryService4 } from "@flowgram.ai/history";
|
|
592
|
+
import { injectable as injectable6, inject as inject3 } from "inversify";
|
|
593
|
+
import { DisposableCollection as DisposableCollection2 } from "@flowgram.ai/utils";
|
|
594
|
+
import { HistoryService as HistoryService3 } from "@flowgram.ai/history";
|
|
723
595
|
import {
|
|
724
|
-
WorkflowDocument as
|
|
596
|
+
WorkflowDocument as WorkflowDocument7,
|
|
725
597
|
WorkflowResetLayoutService as WorkflowResetLayoutService2,
|
|
726
598
|
WorkflowDragService,
|
|
727
599
|
WorkflowOperationBaseService
|
|
728
600
|
} from "@flowgram.ai/free-layout-core";
|
|
729
|
-
import { FlowNodeFormData as FlowNodeFormData3 } from "@flowgram.ai/form-core";
|
|
730
|
-
import { FormManager } from "@flowgram.ai/form-core";
|
|
731
601
|
import { OperationType as OperationType2 } from "@flowgram.ai/document";
|
|
732
602
|
import { PositionData } from "@flowgram.ai/core";
|
|
733
603
|
var FreeHistoryManager = class {
|
|
@@ -735,8 +605,8 @@ var FreeHistoryManager = class {
|
|
|
735
605
|
this._toDispose = new DisposableCollection2();
|
|
736
606
|
}
|
|
737
607
|
onInit(ctx, opts) {
|
|
738
|
-
const document = ctx.get(
|
|
739
|
-
const historyService = ctx.get(
|
|
608
|
+
const document = ctx.get(WorkflowDocument7);
|
|
609
|
+
const historyService = ctx.get(HistoryService3);
|
|
740
610
|
const dragService = ctx.get(WorkflowDragService);
|
|
741
611
|
const resetLayoutService = ctx.get(WorkflowResetLayoutService2);
|
|
742
612
|
if (opts?.limit) {
|
|
@@ -756,21 +626,6 @@ var FreeHistoryManager = class {
|
|
|
756
626
|
this._entityManager.addEntityData(positionData);
|
|
757
627
|
}
|
|
758
628
|
}),
|
|
759
|
-
this._formManager ? this._formManager.onFormModelWillInit(({ model, data }) => {
|
|
760
|
-
const node = model.flowNodeEntity;
|
|
761
|
-
const formData = node.getData(FlowNodeFormData3);
|
|
762
|
-
if (formData) {
|
|
763
|
-
this._entityManager.setValue(formData, cloneDeep4(data));
|
|
764
|
-
this._toDispose.push(
|
|
765
|
-
formData.onDetailChange((event) => {
|
|
766
|
-
this._changeNodeDataHandler.handle({
|
|
767
|
-
...event,
|
|
768
|
-
node
|
|
769
|
-
});
|
|
770
|
-
})
|
|
771
|
-
);
|
|
772
|
-
}
|
|
773
|
-
}) : Disposable.NULL,
|
|
774
629
|
document.onContentChange((event) => {
|
|
775
630
|
this._changeContentHandler.handle(event, ctx);
|
|
776
631
|
}),
|
|
@@ -831,26 +686,19 @@ var FreeHistoryManager = class {
|
|
|
831
686
|
}
|
|
832
687
|
};
|
|
833
688
|
__decorateClass([
|
|
834
|
-
|
|
689
|
+
inject3(DragNodesHandler)
|
|
835
690
|
], FreeHistoryManager.prototype, "_dragNodesHandler", 2);
|
|
836
691
|
__decorateClass([
|
|
837
|
-
|
|
838
|
-
], FreeHistoryManager.prototype, "_changeNodeDataHandler", 2);
|
|
839
|
-
__decorateClass([
|
|
840
|
-
inject4(ChangeContentHandler)
|
|
692
|
+
inject3(ChangeContentHandler)
|
|
841
693
|
], FreeHistoryManager.prototype, "_changeContentHandler", 2);
|
|
842
694
|
__decorateClass([
|
|
843
|
-
|
|
695
|
+
inject3(HistoryEntityManager)
|
|
844
696
|
], FreeHistoryManager.prototype, "_entityManager", 2);
|
|
845
697
|
__decorateClass([
|
|
846
|
-
|
|
847
|
-
optional()
|
|
848
|
-
], FreeHistoryManager.prototype, "_formManager", 2);
|
|
849
|
-
__decorateClass([
|
|
850
|
-
inject4(WorkflowOperationBaseService)
|
|
698
|
+
inject3(WorkflowOperationBaseService)
|
|
851
699
|
], FreeHistoryManager.prototype, "_operationService", 2);
|
|
852
700
|
FreeHistoryManager = __decorateClass([
|
|
853
|
-
|
|
701
|
+
injectable6()
|
|
854
702
|
], FreeHistoryManager);
|
|
855
703
|
|
|
856
704
|
// src/create-free-history-plugin.ts
|
|
@@ -861,7 +709,6 @@ var createFreeHistoryPlugin = definePluginCreator({
|
|
|
861
709
|
bind(FreeHistoryManager).toSelf().inSingletonScope();
|
|
862
710
|
bind(HistoryEntityManager).toSelf().inSingletonScope();
|
|
863
711
|
bind(DragNodesHandler).toSelf().inSingletonScope();
|
|
864
|
-
bind(ChangeNodeDataHandler).toSelf().inSingletonScope();
|
|
865
712
|
bind(ChangeContentHandler).toSelf().inSingletonScope();
|
|
866
713
|
},
|
|
867
714
|
onInit(ctx, opts) {
|
|
@@ -883,9 +730,9 @@ export * from "@flowgram.ai/history";
|
|
|
883
730
|
// src/hooks/use-undo-redo.tsx
|
|
884
731
|
import { useEffect, useState } from "react";
|
|
885
732
|
import { useService } from "@flowgram.ai/core";
|
|
886
|
-
import { HistoryService as
|
|
733
|
+
import { HistoryService as HistoryService4 } from "@flowgram.ai/history";
|
|
887
734
|
function useUndoRedo() {
|
|
888
|
-
const historyService = useService(
|
|
735
|
+
const historyService = useService(HistoryService4);
|
|
889
736
|
const [canUndo, setCanUndo] = useState(false);
|
|
890
737
|
const [canRedo, setCanRedo] = useState(false);
|
|
891
738
|
useEffect(() => {
|