@craftile/core 1.3.1 → 1.3.2
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/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@craftile/core",
|
|
3
|
-
"version": "1.3.
|
|
3
|
+
"version": "1.3.2",
|
|
4
4
|
"description": "Framework-agnostic block editor engine for Craftile",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"craftile",
|
|
@@ -26,8 +26,8 @@
|
|
|
26
26
|
"src"
|
|
27
27
|
],
|
|
28
28
|
"dependencies": {
|
|
29
|
-
"@craftile/event-bus": "1.3.
|
|
30
|
-
"@craftile/types": "1.3.
|
|
29
|
+
"@craftile/event-bus": "1.3.2",
|
|
30
|
+
"@craftile/types": "1.3.2"
|
|
31
31
|
},
|
|
32
32
|
"devDependencies": {
|
|
33
33
|
"vitest": "^3.2.4",
|
|
@@ -13,16 +13,20 @@ export class DuplicateBlockCommand implements Command {
|
|
|
13
13
|
private blockId: string;
|
|
14
14
|
|
|
15
15
|
// State for reverting
|
|
16
|
-
private duplicatedBlockId
|
|
16
|
+
private duplicatedBlockId: string;
|
|
17
17
|
private duplicatedBlock?: Block;
|
|
18
18
|
private parentId?: string | null;
|
|
19
19
|
private insertIndex!: number;
|
|
20
20
|
private regionId?: string | null;
|
|
21
21
|
private emit: EngineEmitFn;
|
|
22
22
|
|
|
23
|
+
// Original descendant ID -> copy ID, reused on redo so the copy keeps its IDs
|
|
24
|
+
private cloneIds = new Map<string, string>();
|
|
25
|
+
|
|
23
26
|
constructor(getPage: () => Page, options: DuplicateBlockOptions) {
|
|
24
27
|
this.getPage = getPage;
|
|
25
28
|
this.blockId = options.blockId;
|
|
29
|
+
this.duplicatedBlockId = generateId();
|
|
26
30
|
this.emit = options.emit;
|
|
27
31
|
}
|
|
28
32
|
|
|
@@ -33,8 +37,6 @@ export class DuplicateBlockCommand implements Command {
|
|
|
33
37
|
throw new Error(`Block not found: ${this.blockId}`);
|
|
34
38
|
}
|
|
35
39
|
|
|
36
|
-
this.duplicatedBlockId = generateId();
|
|
37
|
-
|
|
38
40
|
this.duplicatedBlock = this.cloneBlockWithNewIds(
|
|
39
41
|
page,
|
|
40
42
|
originalBlock,
|
|
@@ -62,6 +64,13 @@ export class DuplicateBlockCommand implements Command {
|
|
|
62
64
|
}
|
|
63
65
|
|
|
64
66
|
this.removeDuplicatedBlock(this.getPage());
|
|
67
|
+
|
|
68
|
+
this.emit('block:remove', {
|
|
69
|
+
blockId: this.duplicatedBlockId,
|
|
70
|
+
block: this.duplicatedBlock,
|
|
71
|
+
parentId: this.parentId || undefined,
|
|
72
|
+
regionId: this.regionId || undefined,
|
|
73
|
+
});
|
|
65
74
|
}
|
|
66
75
|
|
|
67
76
|
getBlockId(): string {
|
|
@@ -100,7 +109,11 @@ export class DuplicateBlockCommand implements Command {
|
|
|
100
109
|
for (const childId of block.children) {
|
|
101
110
|
const childBlock = page.blocks[childId];
|
|
102
111
|
if (childBlock) {
|
|
103
|
-
|
|
112
|
+
let newChildId = this.cloneIds.get(childId);
|
|
113
|
+
if (!newChildId) {
|
|
114
|
+
newChildId = generateId();
|
|
115
|
+
this.cloneIds.set(childId, newChildId);
|
|
116
|
+
}
|
|
104
117
|
this.cloneBlockWithNewIds(page, childBlock, newChildId, newId);
|
|
105
118
|
clonedBlock.children.push(newChildId);
|
|
106
119
|
}
|
|
@@ -31,6 +31,10 @@ export class InsertBlockFromPresetCommand implements Command {
|
|
|
31
31
|
private emit: EngineEmitFn;
|
|
32
32
|
private createdBlockIds: string[] = [];
|
|
33
33
|
|
|
34
|
+
// Child IDs in creation order, reused on redo so children keep their IDs
|
|
35
|
+
private childIds: string[] = [];
|
|
36
|
+
private childIdIndex = 0;
|
|
37
|
+
|
|
34
38
|
constructor(getPage: () => Page, options: InsertBlockFromPresetOptions) {
|
|
35
39
|
this.getPage = getPage;
|
|
36
40
|
this.blockType = options.blockType;
|
|
@@ -75,6 +79,9 @@ export class InsertBlockFromPresetCommand implements Command {
|
|
|
75
79
|
|
|
76
80
|
const blockSchema = this.blocksManager.get(this.blockType);
|
|
77
81
|
|
|
82
|
+
this.createdBlockIds = [];
|
|
83
|
+
this.childIdIndex = 0;
|
|
84
|
+
|
|
78
85
|
if (this.presetData) {
|
|
79
86
|
this.insertedBlock = {
|
|
80
87
|
...structuredClone(this.presetData),
|
|
@@ -185,7 +192,7 @@ export class InsertBlockFromPresetCommand implements Command {
|
|
|
185
192
|
const childIds: string[] = [];
|
|
186
193
|
|
|
187
194
|
for (const structure of structures) {
|
|
188
|
-
const childId =
|
|
195
|
+
const childId = this.nextChildId();
|
|
189
196
|
const childSchema = this.blocksManager.get(structure.type);
|
|
190
197
|
|
|
191
198
|
if (!childSchema) {
|
|
@@ -220,6 +227,14 @@ export class InsertBlockFromPresetCommand implements Command {
|
|
|
220
227
|
return childIds;
|
|
221
228
|
}
|
|
222
229
|
|
|
230
|
+
private nextChildId(): string {
|
|
231
|
+
if (this.childIdIndex === this.childIds.length) {
|
|
232
|
+
this.childIds.push(generateId());
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
return this.childIds[this.childIdIndex++];
|
|
236
|
+
}
|
|
237
|
+
|
|
223
238
|
private buildProperties(blockSchema?: BlockSchema, presetProperties?: Record<string, any>): Record<string, any> {
|
|
224
239
|
const properties: Record<string, any> = {};
|
|
225
240
|
|
|
@@ -23,6 +23,8 @@ export class MoveBlockCommand implements Command {
|
|
|
23
23
|
private originalParentId?: string;
|
|
24
24
|
private originalIndex!: number;
|
|
25
25
|
private originalRegionId?: string;
|
|
26
|
+
private resolvedIndex!: number;
|
|
27
|
+
private resolvedRegionId?: string;
|
|
26
28
|
|
|
27
29
|
private emit: EngineEmitFn;
|
|
28
30
|
|
|
@@ -66,12 +68,14 @@ export class MoveBlockCommand implements Command {
|
|
|
66
68
|
}
|
|
67
69
|
|
|
68
70
|
this.moved = true;
|
|
71
|
+
this.resolvedIndex = target.index;
|
|
72
|
+
this.resolvedRegionId = target.kind === 'region' ? target.regionId : undefined;
|
|
69
73
|
|
|
70
74
|
this.emit('block:move', {
|
|
71
75
|
blockId: this.blockId,
|
|
72
76
|
targetParentId: this.targetParentId,
|
|
73
|
-
targetIndex: this.
|
|
74
|
-
targetRegionId:
|
|
77
|
+
targetIndex: this.resolvedIndex,
|
|
78
|
+
targetRegionId: this.resolvedRegionId,
|
|
75
79
|
sourceParentId: this.originalParentId || null,
|
|
76
80
|
sourceRegionId: this.originalRegionId || null,
|
|
77
81
|
sourceIndex: this.originalIndex,
|
|
@@ -185,8 +189,8 @@ export class MoveBlockCommand implements Command {
|
|
|
185
189
|
targetIndex: this.originalIndex,
|
|
186
190
|
targetRegionId: this.originalRegionId,
|
|
187
191
|
sourceParentId: this.targetParentId || null,
|
|
188
|
-
sourceRegionId: this.
|
|
189
|
-
sourceIndex: this.
|
|
192
|
+
sourceRegionId: this.resolvedRegionId || null,
|
|
193
|
+
sourceIndex: this.resolvedIndex,
|
|
190
194
|
});
|
|
191
195
|
}
|
|
192
196
|
|
|
@@ -11,6 +11,7 @@ export class RemoveBlockCommand implements Command {
|
|
|
11
11
|
private getPage: () => Page;
|
|
12
12
|
private blockId: string;
|
|
13
13
|
private removedBlock?: Block;
|
|
14
|
+
private removedDescendants: Block[] = [];
|
|
14
15
|
private originalIndex?: number;
|
|
15
16
|
private originalParentId?: string;
|
|
16
17
|
private regionId?: string;
|
|
@@ -49,6 +50,11 @@ export class RemoveBlockCommand implements Command {
|
|
|
49
50
|
}
|
|
50
51
|
}
|
|
51
52
|
|
|
53
|
+
this.removedDescendants = this.collectDescendants(page, this.removedBlock);
|
|
54
|
+
for (const descendant of this.removedDescendants) {
|
|
55
|
+
delete page.blocks[descendant.id];
|
|
56
|
+
}
|
|
57
|
+
|
|
52
58
|
delete page.blocks[this.blockId];
|
|
53
59
|
|
|
54
60
|
this.emit('block:remove', {
|
|
@@ -67,6 +73,9 @@ export class RemoveBlockCommand implements Command {
|
|
|
67
73
|
const page = this.getPage();
|
|
68
74
|
|
|
69
75
|
page.blocks[this.blockId] = this.removedBlock;
|
|
76
|
+
for (const descendant of this.removedDescendants) {
|
|
77
|
+
page.blocks[descendant.id] = descendant;
|
|
78
|
+
}
|
|
70
79
|
|
|
71
80
|
if (this.originalParentId) {
|
|
72
81
|
const parent = page.blocks[this.originalParentId];
|
|
@@ -96,4 +105,17 @@ export class RemoveBlockCommand implements Command {
|
|
|
96
105
|
getRemovedBlock(): Block | undefined {
|
|
97
106
|
return this.removedBlock;
|
|
98
107
|
}
|
|
108
|
+
|
|
109
|
+
private collectDescendants(page: Page, block: Block): Block[] {
|
|
110
|
+
const descendants: Block[] = [];
|
|
111
|
+
|
|
112
|
+
for (const childId of block.children) {
|
|
113
|
+
const child = page.blocks[childId];
|
|
114
|
+
if (child) {
|
|
115
|
+
descendants.push(child, ...this.collectDescendants(page, child));
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
return descendants;
|
|
120
|
+
}
|
|
99
121
|
}
|