sketchmark 2.1.7 → 2.1.8
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/bin/editor-ui.cjs +404 -329
- package/bin/editor-ui.d.ts +0 -1
- package/bin/sketchmark.cjs +84 -28
- package/dist/src/edit.d.ts +33 -0
- package/dist/src/edit.js +216 -0
- package/dist/src/index.d.ts +1 -0
- package/dist/src/index.js +5 -0
- package/dist/tests/run.js +52 -0
- package/package.json +6 -1
package/bin/editor-ui.d.ts
CHANGED
package/bin/sketchmark.cjs
CHANGED
|
@@ -134,22 +134,68 @@ async function edit(args, options = {}) {
|
|
|
134
134
|
sendJson(response, 200, editorDocumentPayload(doc));
|
|
135
135
|
return;
|
|
136
136
|
}
|
|
137
|
-
if (request.method === "POST" && url.pathname === "/api/property") {
|
|
138
|
-
if (options.readOnly) {
|
|
139
|
-
sendJson(response, 403, { ok: false, error: "Preview mode is read-only." });
|
|
140
|
-
return;
|
|
141
|
-
}
|
|
142
|
-
const payload = await readJson(request);
|
|
143
|
-
const doc = core.setElementProperty(loadDocument(inputPath), requiredString(payload.id, "id"), requiredString(payload.property, "property"), normalizeMotionValue(payload.value));
|
|
144
|
-
saveDocument(inputPath, doc);
|
|
145
|
-
sendJson(response, 200, editorDocumentPayload(doc));
|
|
146
|
-
return;
|
|
147
|
-
}
|
|
148
|
-
if (request.method === "POST" && url.pathname === "/api/
|
|
149
|
-
if (options.readOnly) {
|
|
150
|
-
sendJson(response, 403, { ok: false, error: "Preview mode is read-only." });
|
|
151
|
-
return;
|
|
152
|
-
}
|
|
137
|
+
if (request.method === "POST" && url.pathname === "/api/property") {
|
|
138
|
+
if (options.readOnly) {
|
|
139
|
+
sendJson(response, 403, { ok: false, error: "Preview mode is read-only." });
|
|
140
|
+
return;
|
|
141
|
+
}
|
|
142
|
+
const payload = await readJson(request);
|
|
143
|
+
const doc = core.setElementProperty(loadDocument(inputPath), requiredString(payload.id, "id"), requiredString(payload.property, "property"), normalizeMotionValue(payload.value));
|
|
144
|
+
saveDocument(inputPath, doc);
|
|
145
|
+
sendJson(response, 200, editorDocumentPayload(doc));
|
|
146
|
+
return;
|
|
147
|
+
}
|
|
148
|
+
if (request.method === "POST" && url.pathname === "/api/element") {
|
|
149
|
+
if (options.readOnly) {
|
|
150
|
+
sendJson(response, 403, { ok: false, error: "Preview mode is read-only." });
|
|
151
|
+
return;
|
|
152
|
+
}
|
|
153
|
+
const payload = await readJson(request);
|
|
154
|
+
const result = core.insertElementPreset(loadDocument(inputPath), requiredString(payload.preset, "preset"), {
|
|
155
|
+
parentId: optionalString(payload.parentId),
|
|
156
|
+
id: optionalString(payload.id),
|
|
157
|
+
index: optionalNumber(payload.index)
|
|
158
|
+
});
|
|
159
|
+
saveDocument(inputPath, result.document);
|
|
160
|
+
sendJson(response, 200, { ...editorDocumentPayload(result.document), insertedId: result.element.id, parentId: result.parentId || "" });
|
|
161
|
+
return;
|
|
162
|
+
}
|
|
163
|
+
if (request.method === "POST" && url.pathname === "/api/reorder") {
|
|
164
|
+
if (options.readOnly) {
|
|
165
|
+
sendJson(response, 403, { ok: false, error: "Preview mode is read-only." });
|
|
166
|
+
return;
|
|
167
|
+
}
|
|
168
|
+
const payload = await readJson(request);
|
|
169
|
+
const result = core.reorderElement(loadDocument(inputPath), requiredString(payload.id, "id"), {
|
|
170
|
+
direction: optionalString(payload.direction),
|
|
171
|
+
toIndex: optionalNumber(payload.index)
|
|
172
|
+
});
|
|
173
|
+
saveDocument(inputPath, result.document);
|
|
174
|
+
sendJson(response, 200, {
|
|
175
|
+
...editorDocumentPayload(result.document),
|
|
176
|
+
reorderedId: result.id,
|
|
177
|
+
parentId: result.parentId || "",
|
|
178
|
+
layerIndex: result.index,
|
|
179
|
+
previousLayerIndex: result.previousIndex
|
|
180
|
+
});
|
|
181
|
+
return;
|
|
182
|
+
}
|
|
183
|
+
if (request.method === "POST" && url.pathname === "/api/delete-element") {
|
|
184
|
+
if (options.readOnly) {
|
|
185
|
+
sendJson(response, 403, { ok: false, error: "Preview mode is read-only." });
|
|
186
|
+
return;
|
|
187
|
+
}
|
|
188
|
+
const payload = await readJson(request);
|
|
189
|
+
const result = core.deleteElement(loadDocument(inputPath), requiredString(payload.id, "id"));
|
|
190
|
+
saveDocument(inputPath, result.document);
|
|
191
|
+
sendJson(response, 200, { ...editorDocumentPayload(result.document), deletedId: result.id, parentId: result.parentId || "" });
|
|
192
|
+
return;
|
|
193
|
+
}
|
|
194
|
+
if (request.method === "POST" && url.pathname === "/api/keyframe") {
|
|
195
|
+
if (options.readOnly) {
|
|
196
|
+
sendJson(response, 403, { ok: false, error: "Preview mode is read-only." });
|
|
197
|
+
return;
|
|
198
|
+
}
|
|
153
199
|
const payload = await readJson(request);
|
|
154
200
|
const curve = curveFromPayload(payload);
|
|
155
201
|
const doc = core.setTimelineKeyframe(
|
|
@@ -538,18 +584,28 @@ function readJson(request) {
|
|
|
538
584
|
});
|
|
539
585
|
}
|
|
540
586
|
|
|
541
|
-
function requiredString(value, name) {
|
|
542
|
-
if (typeof value !== "string" || !value) throw new Error(`${name} must be a non-empty string.`);
|
|
543
|
-
return value;
|
|
544
|
-
}
|
|
545
|
-
|
|
546
|
-
function
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
587
|
+
function requiredString(value, name) {
|
|
588
|
+
if (typeof value !== "string" || !value) throw new Error(`${name} must be a non-empty string.`);
|
|
589
|
+
return value;
|
|
590
|
+
}
|
|
591
|
+
|
|
592
|
+
function optionalString(value) {
|
|
593
|
+
return typeof value === "string" && value ? value : undefined;
|
|
594
|
+
}
|
|
595
|
+
|
|
596
|
+
function requiredNumber(value, name) {
|
|
597
|
+
const number = Number(value);
|
|
598
|
+
if (!Number.isFinite(number)) throw new Error(`${name} must be a finite number.`);
|
|
599
|
+
return number;
|
|
600
|
+
}
|
|
601
|
+
|
|
602
|
+
function optionalNumber(value) {
|
|
603
|
+
if (value === undefined || value === null || value === "") return undefined;
|
|
604
|
+
const number = Number(value);
|
|
605
|
+
return Number.isFinite(number) ? number : undefined;
|
|
606
|
+
}
|
|
607
|
+
|
|
608
|
+
function applyCanvasPatch(document, payload) {
|
|
553
609
|
if (!payload || typeof payload !== "object" || Array.isArray(payload)) {
|
|
554
610
|
throw new Error("canvas payload must be an object.");
|
|
555
611
|
}
|
package/dist/src/edit.d.ts
CHANGED
|
@@ -12,8 +12,41 @@ export interface SetKeyframeOptions {
|
|
|
12
12
|
curve?: TimelineCurve;
|
|
13
13
|
ease?: string;
|
|
14
14
|
}
|
|
15
|
+
export type ElementPresetKind = "text" | "rectangle" | "circle" | "line" | "path" | "point" | "group";
|
|
16
|
+
export interface InsertElementPresetOptions {
|
|
17
|
+
id?: string;
|
|
18
|
+
parentId?: string | null;
|
|
19
|
+
index?: number;
|
|
20
|
+
}
|
|
21
|
+
export interface InsertElementPresetResult {
|
|
22
|
+
document: VisualDocument;
|
|
23
|
+
element: VisualElement;
|
|
24
|
+
parentId?: string;
|
|
25
|
+
}
|
|
26
|
+
export type ReorderElementDirection = "backward" | "forward" | "back" | "front";
|
|
27
|
+
export interface ReorderElementOptions {
|
|
28
|
+
direction?: ReorderElementDirection | string;
|
|
29
|
+
toIndex?: number;
|
|
30
|
+
}
|
|
31
|
+
export interface ReorderElementResult {
|
|
32
|
+
document: VisualDocument;
|
|
33
|
+
id: string;
|
|
34
|
+
index: number;
|
|
35
|
+
previousIndex: number;
|
|
36
|
+
parentId?: string;
|
|
37
|
+
}
|
|
38
|
+
export interface DeleteElementResult {
|
|
39
|
+
document: VisualDocument;
|
|
40
|
+
element: VisualElement;
|
|
41
|
+
id: string;
|
|
42
|
+
index: number;
|
|
43
|
+
parentId?: string;
|
|
44
|
+
}
|
|
15
45
|
export declare function listElementReferences(document: VisualDocument): ElementReference[];
|
|
16
46
|
export declare function findElementById(document: VisualDocument, id: string): VisualElement | undefined;
|
|
47
|
+
export declare function insertElementPreset(document: VisualDocument, preset: ElementPresetKind | string, options?: InsertElementPresetOptions): InsertElementPresetResult;
|
|
48
|
+
export declare function reorderElement(document: VisualDocument, id: string, options?: ReorderElementOptions): ReorderElementResult;
|
|
49
|
+
export declare function deleteElement(document: VisualDocument, id: string): DeleteElementResult;
|
|
17
50
|
export declare function setElementProperty(document: VisualDocument, id: string, property: string, value: MotionValue): VisualDocument;
|
|
18
51
|
export declare function setTimelineKeyframe(document: VisualDocument, id: string, property: string, time: number, value: MotionValue, options?: SetKeyframeOptions): VisualDocument;
|
|
19
52
|
export declare function removeTimelineKeyframe(document: VisualDocument, id: string, property: string, time: number): VisualDocument;
|
package/dist/src/edit.js
CHANGED
|
@@ -2,6 +2,9 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.listElementReferences = listElementReferences;
|
|
4
4
|
exports.findElementById = findElementById;
|
|
5
|
+
exports.insertElementPreset = insertElementPreset;
|
|
6
|
+
exports.reorderElement = reorderElement;
|
|
7
|
+
exports.deleteElement = deleteElement;
|
|
5
8
|
exports.setElementProperty = setElementProperty;
|
|
6
9
|
exports.setTimelineKeyframe = setTimelineKeyframe;
|
|
7
10
|
exports.removeTimelineKeyframe = removeTimelineKeyframe;
|
|
@@ -28,6 +31,67 @@ function findElementById(document, id) {
|
|
|
28
31
|
});
|
|
29
32
|
return found;
|
|
30
33
|
}
|
|
34
|
+
function insertElementPreset(document, preset, options = {}) {
|
|
35
|
+
const next = (0, utils_1.clone)(document);
|
|
36
|
+
repairLegacyTimelineCurves(next);
|
|
37
|
+
next.elements ?? (next.elements = []);
|
|
38
|
+
const parentId = typeof options.parentId === "string" && options.parentId ? options.parentId : "";
|
|
39
|
+
const parent = parentId ? requireElement(next, parentId) : undefined;
|
|
40
|
+
if (parent && parent.type !== "group")
|
|
41
|
+
throw new Error(`Element '${parentId}' is not a group.`);
|
|
42
|
+
const id = uniqueElementId(next, options.id || presetBaseId(preset));
|
|
43
|
+
const element = createPresetElement(preset, id, insertionPoint(next, parent));
|
|
44
|
+
const target = parent ? parent.children : next.elements;
|
|
45
|
+
insertAt(target, element, options.index);
|
|
46
|
+
assertValid(next);
|
|
47
|
+
return { document: next, element: (0, utils_1.clone)(element), ...(parentId ? { parentId } : {}) };
|
|
48
|
+
}
|
|
49
|
+
function reorderElement(document, id, options = {}) {
|
|
50
|
+
if (!id)
|
|
51
|
+
throw new Error("id must be a non-empty string.");
|
|
52
|
+
const next = (0, utils_1.clone)(document);
|
|
53
|
+
repairLegacyTimelineCurves(next);
|
|
54
|
+
next.elements ?? (next.elements = []);
|
|
55
|
+
const slot = findElementSlot(next.elements, id);
|
|
56
|
+
if (!slot)
|
|
57
|
+
throw new Error(`Unknown element '${id}'.`);
|
|
58
|
+
const previousIndex = slot.index;
|
|
59
|
+
const nextIndex = layerTargetIndex(slot.index, slot.elements.length, options);
|
|
60
|
+
if (nextIndex !== slot.index) {
|
|
61
|
+
const [element] = slot.elements.splice(slot.index, 1);
|
|
62
|
+
if (element)
|
|
63
|
+
slot.elements.splice(nextIndex, 0, element);
|
|
64
|
+
}
|
|
65
|
+
assertValid(next);
|
|
66
|
+
return {
|
|
67
|
+
document: next,
|
|
68
|
+
id,
|
|
69
|
+
previousIndex,
|
|
70
|
+
index: nextIndex,
|
|
71
|
+
...(slot.parentId ? { parentId: slot.parentId } : {})
|
|
72
|
+
};
|
|
73
|
+
}
|
|
74
|
+
function deleteElement(document, id) {
|
|
75
|
+
if (!id)
|
|
76
|
+
throw new Error("id must be a non-empty string.");
|
|
77
|
+
const next = (0, utils_1.clone)(document);
|
|
78
|
+
repairLegacyTimelineCurves(next);
|
|
79
|
+
next.elements ?? (next.elements = []);
|
|
80
|
+
const slot = findElementSlot(next.elements, id);
|
|
81
|
+
if (!slot)
|
|
82
|
+
throw new Error(`Unknown element '${id}'.`);
|
|
83
|
+
const [element] = slot.elements.splice(slot.index, 1);
|
|
84
|
+
if (!element)
|
|
85
|
+
throw new Error(`Unknown element '${id}'.`);
|
|
86
|
+
assertValid(next);
|
|
87
|
+
return {
|
|
88
|
+
document: next,
|
|
89
|
+
element: (0, utils_1.clone)(element),
|
|
90
|
+
id,
|
|
91
|
+
index: slot.index,
|
|
92
|
+
...(slot.parentId ? { parentId: slot.parentId } : {})
|
|
93
|
+
};
|
|
94
|
+
}
|
|
31
95
|
function setElementProperty(document, id, property, value) {
|
|
32
96
|
const next = (0, utils_1.clone)(document);
|
|
33
97
|
repairLegacyTimelineCurves(next);
|
|
@@ -127,6 +191,158 @@ function requireElement(document, id) {
|
|
|
127
191
|
throw new Error(`Unknown element '${id}'.`);
|
|
128
192
|
return element;
|
|
129
193
|
}
|
|
194
|
+
function findElementSlot(elements, id, parentId = "") {
|
|
195
|
+
for (let index = 0; index < elements.length; index += 1) {
|
|
196
|
+
const element = elements[index];
|
|
197
|
+
if (!element)
|
|
198
|
+
continue;
|
|
199
|
+
if (element.id === id)
|
|
200
|
+
return { elements, index, parentId };
|
|
201
|
+
if (element.type === "group") {
|
|
202
|
+
const found = findElementSlot(element.children, id, element.id || parentId);
|
|
203
|
+
if (found)
|
|
204
|
+
return found;
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
function layerTargetIndex(index, length, options) {
|
|
209
|
+
if (length <= 1)
|
|
210
|
+
return index;
|
|
211
|
+
if (options.toIndex !== undefined) {
|
|
212
|
+
const nextIndex = Math.round(Number(options.toIndex));
|
|
213
|
+
if (!Number.isFinite(nextIndex))
|
|
214
|
+
throw new Error("toIndex must be a finite number.");
|
|
215
|
+
return Math.max(0, Math.min(length - 1, nextIndex));
|
|
216
|
+
}
|
|
217
|
+
switch (options.direction || "forward") {
|
|
218
|
+
case "backward":
|
|
219
|
+
return Math.max(0, index - 1);
|
|
220
|
+
case "forward":
|
|
221
|
+
return Math.min(length - 1, index + 1);
|
|
222
|
+
case "back":
|
|
223
|
+
return 0;
|
|
224
|
+
case "front":
|
|
225
|
+
return length - 1;
|
|
226
|
+
default:
|
|
227
|
+
throw new Error(`Unknown reorder direction '${options.direction}'.`);
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
function createPresetElement(preset, id, point) {
|
|
231
|
+
const x = Math.round(point[0]);
|
|
232
|
+
const y = Math.round(point[1]);
|
|
233
|
+
switch (preset) {
|
|
234
|
+
case "text":
|
|
235
|
+
return {
|
|
236
|
+
id,
|
|
237
|
+
type: "text",
|
|
238
|
+
x,
|
|
239
|
+
y,
|
|
240
|
+
text: "Text",
|
|
241
|
+
align: "center",
|
|
242
|
+
valign: "middle",
|
|
243
|
+
fontSize: 36,
|
|
244
|
+
weight: 700,
|
|
245
|
+
fill: "#111827"
|
|
246
|
+
};
|
|
247
|
+
case "rectangle":
|
|
248
|
+
return {
|
|
249
|
+
id,
|
|
250
|
+
type: "path",
|
|
251
|
+
x,
|
|
252
|
+
y,
|
|
253
|
+
d: "M -80 -50 H 80 V 50 H -80 Z",
|
|
254
|
+
fill: "#dbeafe",
|
|
255
|
+
stroke: "#2563eb",
|
|
256
|
+
strokeWidth: 3
|
|
257
|
+
};
|
|
258
|
+
case "circle":
|
|
259
|
+
return {
|
|
260
|
+
id,
|
|
261
|
+
type: "path",
|
|
262
|
+
x,
|
|
263
|
+
y,
|
|
264
|
+
d: "M 0 -55 A 55 55 0 1 1 0 55 A 55 55 0 1 1 0 -55 Z",
|
|
265
|
+
fill: "#dcfce7",
|
|
266
|
+
stroke: "#16a34a",
|
|
267
|
+
strokeWidth: 3
|
|
268
|
+
};
|
|
269
|
+
case "line":
|
|
270
|
+
return {
|
|
271
|
+
id,
|
|
272
|
+
type: "path",
|
|
273
|
+
x,
|
|
274
|
+
y,
|
|
275
|
+
d: "M -90 0 H 90",
|
|
276
|
+
fill: "none",
|
|
277
|
+
stroke: "#111827",
|
|
278
|
+
strokeWidth: 5,
|
|
279
|
+
strokeCap: "round"
|
|
280
|
+
};
|
|
281
|
+
case "path":
|
|
282
|
+
return {
|
|
283
|
+
id,
|
|
284
|
+
type: "path",
|
|
285
|
+
x,
|
|
286
|
+
y,
|
|
287
|
+
d: "M -80 40 C -40 -50 40 -50 80 40",
|
|
288
|
+
fill: "none",
|
|
289
|
+
stroke: "#7c3aed",
|
|
290
|
+
strokeWidth: 5,
|
|
291
|
+
strokeCap: "round"
|
|
292
|
+
};
|
|
293
|
+
case "point":
|
|
294
|
+
return { id, type: "point", x, y };
|
|
295
|
+
case "group":
|
|
296
|
+
return {
|
|
297
|
+
id,
|
|
298
|
+
type: "group",
|
|
299
|
+
x: Math.round(x - 100),
|
|
300
|
+
y: Math.round(y - 80),
|
|
301
|
+
width: 200,
|
|
302
|
+
height: 160,
|
|
303
|
+
children: []
|
|
304
|
+
};
|
|
305
|
+
default:
|
|
306
|
+
throw new Error(`Unknown element preset '${preset}'.`);
|
|
307
|
+
}
|
|
308
|
+
}
|
|
309
|
+
function insertionPoint(document, parent) {
|
|
310
|
+
if (parent && parent.type === "group") {
|
|
311
|
+
return [Math.max(0, Number(parent.width ?? 0)) / 2, Math.max(0, Number(parent.height ?? 0)) / 2];
|
|
312
|
+
}
|
|
313
|
+
return [Math.max(1, Number(document.canvas?.width ?? 1)) / 2, Math.max(1, Number(document.canvas?.height ?? 1)) / 2];
|
|
314
|
+
}
|
|
315
|
+
function insertAt(elements, element, index) {
|
|
316
|
+
if (Number.isInteger(index) && Number(index) >= 0 && Number(index) <= elements.length)
|
|
317
|
+
elements.splice(Number(index), 0, element);
|
|
318
|
+
else
|
|
319
|
+
elements.push(element);
|
|
320
|
+
}
|
|
321
|
+
function uniqueElementId(document, base) {
|
|
322
|
+
const ids = new Set();
|
|
323
|
+
visitElements(document.elements ?? [], (element) => {
|
|
324
|
+
if (element.id)
|
|
325
|
+
ids.add(element.id);
|
|
326
|
+
});
|
|
327
|
+
const normalized = presetBaseId(base);
|
|
328
|
+
if (!ids.has(normalized))
|
|
329
|
+
return normalized;
|
|
330
|
+
for (let index = 2; index < 10000; index += 1) {
|
|
331
|
+
const candidate = `${normalized}_${index}`;
|
|
332
|
+
if (!ids.has(candidate))
|
|
333
|
+
return candidate;
|
|
334
|
+
}
|
|
335
|
+
throw new Error(`Could not generate a unique id for '${normalized}'.`);
|
|
336
|
+
}
|
|
337
|
+
function presetBaseId(value) {
|
|
338
|
+
const text = String(value || "element")
|
|
339
|
+
.trim()
|
|
340
|
+
.toLowerCase()
|
|
341
|
+
.replace(/[^a-z0-9_.-]+/g, "_")
|
|
342
|
+
.replace(/^[^a-z_]+/i, "")
|
|
343
|
+
.replace(/^_+|_+$/g, "");
|
|
344
|
+
return text || "element";
|
|
345
|
+
}
|
|
130
346
|
function applyProperty(element, property, value) {
|
|
131
347
|
(0, animatable_1.applyPropertyValue)(element, property, value);
|
|
132
348
|
}
|
package/dist/src/index.d.ts
CHANGED
|
@@ -5,6 +5,7 @@ export * from "./diagnostics";
|
|
|
5
5
|
export * from "./schema";
|
|
6
6
|
export * from "./keyframes";
|
|
7
7
|
export * from "./edit";
|
|
8
|
+
export { deleteElement, insertElementPreset, reorderElement } from "./edit";
|
|
8
9
|
export * from "./animatable";
|
|
9
10
|
export * from "./render/svg";
|
|
10
11
|
export * from "./render/html";
|
package/dist/src/index.js
CHANGED
|
@@ -14,6 +14,7 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
|
14
14
|
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
15
15
|
};
|
|
16
16
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
+
exports.reorderElement = exports.insertElementPreset = exports.deleteElement = void 0;
|
|
17
18
|
__exportStar(require("./types"), exports);
|
|
18
19
|
__exportStar(require("./validate"), exports);
|
|
19
20
|
__exportStar(require("./normalize"), exports);
|
|
@@ -21,6 +22,10 @@ __exportStar(require("./diagnostics"), exports);
|
|
|
21
22
|
__exportStar(require("./schema"), exports);
|
|
22
23
|
__exportStar(require("./keyframes"), exports);
|
|
23
24
|
__exportStar(require("./edit"), exports);
|
|
25
|
+
var edit_1 = require("./edit");
|
|
26
|
+
Object.defineProperty(exports, "deleteElement", { enumerable: true, get: function () { return edit_1.deleteElement; } });
|
|
27
|
+
Object.defineProperty(exports, "insertElementPreset", { enumerable: true, get: function () { return edit_1.insertElementPreset; } });
|
|
28
|
+
Object.defineProperty(exports, "reorderElement", { enumerable: true, get: function () { return edit_1.reorderElement; } });
|
|
24
29
|
__exportStar(require("./animatable"), exports);
|
|
25
30
|
__exportStar(require("./render/svg"), exports);
|
|
26
31
|
__exportStar(require("./render/html"), exports);
|
package/dist/tests/run.js
CHANGED
|
@@ -462,6 +462,58 @@ test("compiles per-property curves and timing offsets", () => {
|
|
|
462
462
|
assert(keyframes[1].time === 1.5, `global and property offsets should shift the target keyframe, got ${keyframes[1].time}`);
|
|
463
463
|
assert(near((0, src_1.resolveVisualFrame)(animated, 1).elements[0].x, 0), "hold curve should keep the point at the base value before the target");
|
|
464
464
|
});
|
|
465
|
+
test("inserts element presets at root and inside groups", () => {
|
|
466
|
+
const doc = {
|
|
467
|
+
version: 1,
|
|
468
|
+
canvas: { width: 320, height: 180, duration: 2 },
|
|
469
|
+
elements: [{ id: "group", type: "group", x: 20, y: 30, width: 120, height: 80, children: [] }]
|
|
470
|
+
};
|
|
471
|
+
const rootInsert = (0, src_1.insertElementPreset)(doc, "rectangle");
|
|
472
|
+
assert(rootInsert.element.id === "rectangle", "root preset should use the preset name as id");
|
|
473
|
+
assert((0, src_1.validateVisualDocument)(rootInsert.document).ok, "root preset insert should validate");
|
|
474
|
+
assert((0, src_1.findElementById)(rootInsert.document, "rectangle").type === "path", "rectangle preset should be a path");
|
|
475
|
+
const nestedInsert = (0, src_1.insertElementPreset)(rootInsert.document, "text", { parentId: "group" });
|
|
476
|
+
assert(nestedInsert.parentId === "group", "nested insert should report parent id");
|
|
477
|
+
assert((0, src_1.findElementById)(nestedInsert.document, "group").children.some((item) => item.id === "text"), "nested preset should be added to group children");
|
|
478
|
+
const duplicate = (0, src_1.insertElementPreset)(nestedInsert.document, "text", { parentId: "group" });
|
|
479
|
+
assert(duplicate.element.id === "text_2", "duplicate preset ids should be made unique");
|
|
480
|
+
});
|
|
481
|
+
test("reorders and deletes elements inside their sibling layer", () => {
|
|
482
|
+
const doc = {
|
|
483
|
+
version: 1,
|
|
484
|
+
canvas: { width: 320, height: 180, duration: 2 },
|
|
485
|
+
elements: [
|
|
486
|
+
{ id: "a", type: "point", x: 0, y: 0 },
|
|
487
|
+
{ id: "b", type: "point", x: 10, y: 0 },
|
|
488
|
+
{
|
|
489
|
+
id: "group",
|
|
490
|
+
type: "group",
|
|
491
|
+
x: 20,
|
|
492
|
+
y: 30,
|
|
493
|
+
width: 120,
|
|
494
|
+
height: 80,
|
|
495
|
+
children: [
|
|
496
|
+
{ id: "child1", type: "point", x: 0, y: 0 },
|
|
497
|
+
{ id: "child2", type: "point", x: 10, y: 0 }
|
|
498
|
+
]
|
|
499
|
+
}
|
|
500
|
+
]
|
|
501
|
+
};
|
|
502
|
+
const front = (0, src_1.reorderElement)(doc, "a", { direction: "front" });
|
|
503
|
+
assert(front.previousIndex === 0 && front.index === 2, "root reorder should report old and new indexes");
|
|
504
|
+
assert((front.document.elements ?? []).map((item) => item.id).join(",") === "b,group,a", "front should move the element to the end of root order");
|
|
505
|
+
const backward = (0, src_1.reorderElement)(front.document, "a", { direction: "backward" });
|
|
506
|
+
assert((backward.document.elements ?? []).map((item) => item.id).join(",") === "b,a,group", "backward should move one layer down");
|
|
507
|
+
const nested = (0, src_1.reorderElement)(backward.document, "child1", { direction: "front" });
|
|
508
|
+
assert(nested.parentId === "group", "nested reorder should report parent id");
|
|
509
|
+
assert((0, src_1.findElementById)(nested.document, "group").children.map((item) => item.id).join(",") === "child2,child1", "nested reorder should only affect group children");
|
|
510
|
+
const deleted = (0, src_1.deleteElement)(nested.document, "child2");
|
|
511
|
+
assert(deleted.parentId === "group", "nested delete should report parent id");
|
|
512
|
+
assert(!(0, src_1.findElementById)(deleted.document, "child2"), "deleted child should be removed");
|
|
513
|
+
assert((0, src_1.findElementById)(deleted.document, "group").children.map((item) => item.id).join(",") === "child1", "delete should preserve remaining siblings");
|
|
514
|
+
const deletedGroup = (0, src_1.deleteElement)(deleted.document, "group");
|
|
515
|
+
assert(!(0, src_1.findElementById)(deletedGroup.document, "group") && !(0, src_1.findElementById)(deletedGroup.document, "child1"), "deleting a group should remove its children");
|
|
516
|
+
});
|
|
465
517
|
test("edits nested element properties and timeline keyframes", () => {
|
|
466
518
|
const doc = {
|
|
467
519
|
version: 1,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "sketchmark",
|
|
3
|
-
"version": "2.1.
|
|
3
|
+
"version": "2.1.8",
|
|
4
4
|
"description": "Render kernel for Sketchmark visual documents.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "commonjs",
|
|
@@ -25,6 +25,11 @@
|
|
|
25
25
|
"require": "./dist/src/browser-export.js",
|
|
26
26
|
"default": "./dist/src/browser-export.js"
|
|
27
27
|
},
|
|
28
|
+
"./edit": {
|
|
29
|
+
"types": "./dist/src/edit.d.ts",
|
|
30
|
+
"require": "./dist/src/edit.js",
|
|
31
|
+
"default": "./dist/src/edit.js"
|
|
32
|
+
},
|
|
28
33
|
"./editor": {
|
|
29
34
|
"types": "./bin/editor-ui.d.ts",
|
|
30
35
|
"require": "./bin/editor-ui.cjs",
|