@hyperframes/studio 0.6.79 → 0.6.80
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/index.html
CHANGED
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
<meta name="viewport" content="width=device-width, initial-scale=1.0, viewport-fit=cover" />
|
|
6
6
|
<link rel="icon" type="image/svg+xml" href="/favicon.svg" />
|
|
7
7
|
<title>HyperFrames Studio</title>
|
|
8
|
-
<script type="module" crossorigin src="/assets/index-
|
|
8
|
+
<script type="module" crossorigin src="/assets/index-D8oim9P5.js"></script>
|
|
9
9
|
<link rel="stylesheet" crossorigin href="/assets/index-DcyZuBcU.css">
|
|
10
10
|
</head>
|
|
11
11
|
<body>
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@hyperframes/studio",
|
|
3
|
-
"version": "0.6.
|
|
3
|
+
"version": "0.6.80",
|
|
4
4
|
"description": "",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -31,8 +31,8 @@
|
|
|
31
31
|
"@codemirror/view": "6.40.0",
|
|
32
32
|
"@phosphor-icons/react": "^2.1.10",
|
|
33
33
|
"mediabunny": "^1.45.3",
|
|
34
|
-
"@hyperframes/core": "0.6.
|
|
35
|
-
"@hyperframes/player": "0.6.
|
|
34
|
+
"@hyperframes/core": "0.6.80",
|
|
35
|
+
"@hyperframes/player": "0.6.80"
|
|
36
36
|
},
|
|
37
37
|
"devDependencies": {
|
|
38
38
|
"@types/react": "19",
|
|
@@ -46,7 +46,7 @@
|
|
|
46
46
|
"vite": "^6.4.2",
|
|
47
47
|
"vitest": "^3.2.4",
|
|
48
48
|
"zustand": "^5.0.0",
|
|
49
|
-
"@hyperframes/producer": "0.6.
|
|
49
|
+
"@hyperframes/producer": "0.6.80"
|
|
50
50
|
},
|
|
51
51
|
"peerDependencies": {
|
|
52
52
|
"react": "19",
|
|
@@ -37,6 +37,7 @@ export const PROP_LABELS: Record<string, string> = {
|
|
|
37
37
|
letterSpacing: "Tracking",
|
|
38
38
|
skewX: "Skew X",
|
|
39
39
|
skewY: "Skew Y",
|
|
40
|
+
innerText: "Counter Value",
|
|
40
41
|
};
|
|
41
42
|
|
|
42
43
|
export const PROP_UNITS: Record<string, string> = {
|
|
@@ -65,6 +66,7 @@ export const PROP_TOOLTIPS: Record<string, string> = {
|
|
|
65
66
|
height: "Element height",
|
|
66
67
|
autoAlpha: "Like opacity but hides element completely at 0",
|
|
67
68
|
visibility: "Show or hide the element",
|
|
69
|
+
innerText: "End value for a number roll-up (the number it counts up/down to)",
|
|
68
70
|
};
|
|
69
71
|
|
|
70
72
|
export const EASE_LABELS: Record<string, string> = {
|
|
@@ -154,6 +156,7 @@ export const PROP_CONSTRAINTS: Record<string, { min?: number; max?: number; step
|
|
|
154
156
|
y: { step: 1 },
|
|
155
157
|
fontSize: { min: 1, step: 1 },
|
|
156
158
|
letterSpacing: { step: 0.1 },
|
|
159
|
+
innerText: { step: 1 },
|
|
157
160
|
};
|
|
158
161
|
|
|
159
162
|
export function clampPropertyValue(prop: string, value: number): number {
|
|
@@ -209,6 +209,75 @@ describe("edit history", () => {
|
|
|
209
209
|
expect(state.undo[0].files["index.html"].after).toBe("c");
|
|
210
210
|
});
|
|
211
211
|
|
|
212
|
+
it("coalesces entries with the same coalesceKey within the window (prop: format)", () => {
|
|
213
|
+
const first = buildEditHistoryEntry({
|
|
214
|
+
projectId: "project-1",
|
|
215
|
+
label: "Edit title color",
|
|
216
|
+
kind: "source",
|
|
217
|
+
coalesceKey: "prop:title.color",
|
|
218
|
+
files: {
|
|
219
|
+
"index.html": { before: "a", after: "b" },
|
|
220
|
+
},
|
|
221
|
+
now: 100,
|
|
222
|
+
id: "entry-1",
|
|
223
|
+
});
|
|
224
|
+
const second = buildEditHistoryEntry({
|
|
225
|
+
projectId: "project-1",
|
|
226
|
+
label: "Edit title color",
|
|
227
|
+
kind: "source",
|
|
228
|
+
coalesceKey: "prop:title.color",
|
|
229
|
+
files: {
|
|
230
|
+
"index.html": { before: "b", after: "c" },
|
|
231
|
+
},
|
|
232
|
+
now: 200,
|
|
233
|
+
id: "entry-2",
|
|
234
|
+
});
|
|
235
|
+
|
|
236
|
+
const state = pushEditHistoryEntry(
|
|
237
|
+
pushEditHistoryEntry(createEmptyEditHistory(), first),
|
|
238
|
+
second,
|
|
239
|
+
{ coalesceMs: 1000 },
|
|
240
|
+
);
|
|
241
|
+
|
|
242
|
+
expect(state.undo).toHaveLength(1);
|
|
243
|
+
expect(state.undo[0].id).toBe("entry-2");
|
|
244
|
+
expect(state.undo[0].files["index.html"].before).toBe("a");
|
|
245
|
+
expect(state.undo[0].files["index.html"].after).toBe("c");
|
|
246
|
+
});
|
|
247
|
+
|
|
248
|
+
it("does not coalesce entries with different coalesceKeys (cross-prop separation)", () => {
|
|
249
|
+
const titleEdit = buildEditHistoryEntry({
|
|
250
|
+
projectId: "project-1",
|
|
251
|
+
label: "Edit title color",
|
|
252
|
+
kind: "source",
|
|
253
|
+
coalesceKey: "prop:title.color",
|
|
254
|
+
files: {
|
|
255
|
+
"index.html": { before: "a", after: "b" },
|
|
256
|
+
},
|
|
257
|
+
now: 100,
|
|
258
|
+
id: "entry-title",
|
|
259
|
+
});
|
|
260
|
+
const bodyEdit = buildEditHistoryEntry({
|
|
261
|
+
projectId: "project-1",
|
|
262
|
+
label: "Edit body color",
|
|
263
|
+
kind: "source",
|
|
264
|
+
coalesceKey: "prop:body.color",
|
|
265
|
+
files: {
|
|
266
|
+
"index.html": { before: "b", after: "c" },
|
|
267
|
+
},
|
|
268
|
+
now: 200,
|
|
269
|
+
id: "entry-body",
|
|
270
|
+
});
|
|
271
|
+
|
|
272
|
+
const state = pushEditHistoryEntry(
|
|
273
|
+
pushEditHistoryEntry(createEmptyEditHistory(), titleEdit),
|
|
274
|
+
bodyEdit,
|
|
275
|
+
{ coalesceMs: 1000 },
|
|
276
|
+
);
|
|
277
|
+
|
|
278
|
+
expect(state.undo.map((e) => e.id)).toEqual(["entry-title", "entry-body"]);
|
|
279
|
+
});
|
|
280
|
+
|
|
212
281
|
it("does not coalesce source editor edits outside the coalesce window", () => {
|
|
213
282
|
const first = buildEditHistoryEntry({
|
|
214
283
|
projectId: "project-1",
|
|
@@ -241,4 +310,47 @@ describe("edit history", () => {
|
|
|
241
310
|
|
|
242
311
|
expect(state.undo.map((entry) => entry.id)).toEqual(["entry-1", "entry-2"]);
|
|
243
312
|
});
|
|
313
|
+
|
|
314
|
+
it("coalesces entries exactly at the coalesce boundary (delta === coalesceMs is inclusive)", () => {
|
|
315
|
+
const first = buildEditHistoryEntry({
|
|
316
|
+
projectId: "project-1",
|
|
317
|
+
label: "Edit source",
|
|
318
|
+
kind: "source",
|
|
319
|
+
coalesceKey: "source:index.html",
|
|
320
|
+
files: {
|
|
321
|
+
"index.html": { before: "a", after: "b" },
|
|
322
|
+
},
|
|
323
|
+
now: 100,
|
|
324
|
+
id: "entry-1",
|
|
325
|
+
});
|
|
326
|
+
const second = buildEditHistoryEntry({
|
|
327
|
+
projectId: "project-1",
|
|
328
|
+
label: "Edit source",
|
|
329
|
+
kind: "source",
|
|
330
|
+
coalesceKey: "source:index.html",
|
|
331
|
+
files: {
|
|
332
|
+
"index.html": { before: "b", after: "c" },
|
|
333
|
+
},
|
|
334
|
+
now: 1100, // exactly coalesceMs=1000ms after first
|
|
335
|
+
id: "entry-2",
|
|
336
|
+
});
|
|
337
|
+
|
|
338
|
+
const state = pushEditHistoryEntry(
|
|
339
|
+
pushEditHistoryEntry(createEmptyEditHistory(), first),
|
|
340
|
+
second,
|
|
341
|
+
{ coalesceMs: 1000 },
|
|
342
|
+
);
|
|
343
|
+
|
|
344
|
+
// Boundary is <=: delta of exactly 1000ms coalesces into one entry.
|
|
345
|
+
expect(state.undo).toHaveLength(1);
|
|
346
|
+
expect(state.undo[0].id).toBe("entry-2");
|
|
347
|
+
expect(state.undo[0].files["index.html"].before).toBe("a");
|
|
348
|
+
expect(state.undo[0].files["index.html"].after).toBe("c");
|
|
349
|
+
});
|
|
350
|
+
|
|
351
|
+
it.todo("gesture-start/commit collapses intermediate drag steps into one undo entry");
|
|
352
|
+
|
|
353
|
+
it.todo(
|
|
354
|
+
"origin:applyPatches edits are excluded from undo stack to prevent undo loops (requires SDK session)",
|
|
355
|
+
);
|
|
244
356
|
});
|