@hyperframes/studio 0.6.0-alpha.11 → 0.6.0-alpha.12
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
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
<meta charset="UTF-8" />
|
|
5
5
|
<meta name="viewport" content="width=device-width, initial-scale=1.0, viewport-fit=cover" />
|
|
6
6
|
<title>HyperFrames Studio</title>
|
|
7
|
-
<script type="module" crossorigin src="/assets/index-
|
|
7
|
+
<script type="module" crossorigin src="/assets/index-xdyn_qRZ.js"></script>
|
|
8
8
|
<link rel="stylesheet" crossorigin href="/assets/index-FWg79aJz.css">
|
|
9
9
|
</head>
|
|
10
10
|
<body>
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@hyperframes/studio",
|
|
3
|
-
"version": "0.6.0-alpha.
|
|
3
|
+
"version": "0.6.0-alpha.12",
|
|
4
4
|
"description": "",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -32,8 +32,8 @@
|
|
|
32
32
|
"@phosphor-icons/react": "^2.1.10",
|
|
33
33
|
"codemirror": "^6.0.1",
|
|
34
34
|
"motion": "^12.38.0",
|
|
35
|
-
"@hyperframes/
|
|
36
|
-
"@hyperframes/
|
|
35
|
+
"@hyperframes/core": "0.6.0-alpha.12",
|
|
36
|
+
"@hyperframes/player": "0.6.0-alpha.12"
|
|
37
37
|
},
|
|
38
38
|
"devDependencies": {
|
|
39
39
|
"@types/react": "^19.0.0",
|
|
@@ -47,7 +47,7 @@
|
|
|
47
47
|
"vite": "^6.4.2",
|
|
48
48
|
"vitest": "^3.2.4",
|
|
49
49
|
"zustand": "^5.0.0",
|
|
50
|
-
"@hyperframes/producer": "0.6.0-alpha.
|
|
50
|
+
"@hyperframes/producer": "0.6.0-alpha.12"
|
|
51
51
|
},
|
|
52
52
|
"peerDependencies": {
|
|
53
53
|
"react": "^18.0.0 || ^19.0.0",
|
package/src/App.tsx
CHANGED
|
@@ -157,6 +157,12 @@ function getTimelineElementLabel(element: TimelineElement): string {
|
|
|
157
157
|
return element.label || element.id || element.tag;
|
|
158
158
|
}
|
|
159
159
|
|
|
160
|
+
function confirmElementDelete(label: string, kind: "timeline clip" | "element"): boolean {
|
|
161
|
+
return window.confirm(
|
|
162
|
+
`Delete ${kind} "${label}"?\n\nThis removes it from the project source. You can use Undo to restore it.`,
|
|
163
|
+
);
|
|
164
|
+
}
|
|
165
|
+
|
|
160
166
|
type RightPanelTab = "design" | "motion" | "renders";
|
|
161
167
|
|
|
162
168
|
const GENERIC_FONT_FAMILIES = new Set([
|
|
@@ -1780,6 +1786,8 @@ export function StudioApp() {
|
|
|
1780
1786
|
async (element: TimelineElement) => {
|
|
1781
1787
|
const pid = projectIdRef.current;
|
|
1782
1788
|
if (!pid) throw new Error("No active project");
|
|
1789
|
+
const label = getTimelineElementLabel(element);
|
|
1790
|
+
if (!confirmElementDelete(label, "timeline clip")) return;
|
|
1783
1791
|
|
|
1784
1792
|
const targetPath = element.sourceFile || activeCompPath || "index.html";
|
|
1785
1793
|
try {
|
|
@@ -1877,6 +1885,7 @@ export function StudioApp() {
|
|
|
1877
1885
|
);
|
|
1878
1886
|
usePlayerStore.getState().setSelectedElementId(null);
|
|
1879
1887
|
setRefreshKey((k) => k + 1);
|
|
1888
|
+
showToast(`Deleted ${label}. Use Undo to restore it.`, "info");
|
|
1880
1889
|
} catch (error) {
|
|
1881
1890
|
const message = error instanceof Error ? error.message : "Failed to delete timeline clip";
|
|
1882
1891
|
showToast(message);
|
|
@@ -1889,6 +1898,8 @@ export function StudioApp() {
|
|
|
1889
1898
|
async (selection: DomEditSelection) => {
|
|
1890
1899
|
const pid = projectIdRef.current;
|
|
1891
1900
|
if (!pid) return;
|
|
1901
|
+
const label = selection.label || selection.id || selection.selector || selection.tagName;
|
|
1902
|
+
if (!confirmElementDelete(label, "element")) return;
|
|
1892
1903
|
|
|
1893
1904
|
const targetPath = selection.sourceFile || activeCompPath || "index.html";
|
|
1894
1905
|
try {
|
|
@@ -1946,6 +1957,7 @@ export function StudioApp() {
|
|
|
1946
1957
|
setDomEditGroupSelections([]);
|
|
1947
1958
|
usePlayerStore.getState().setSelectedElementId(null);
|
|
1948
1959
|
setRefreshKey((k) => k + 1);
|
|
1960
|
+
showToast(`Deleted ${label}. Use Undo to restore it.`, "info");
|
|
1949
1961
|
} catch (error) {
|
|
1950
1962
|
const message = error instanceof Error ? error.message : "Failed to delete element";
|
|
1951
1963
|
showToast(message);
|
|
@@ -4,10 +4,8 @@ import {
|
|
|
4
4
|
buildStrokeWidthStyleUpdates,
|
|
5
5
|
getClipPathInsetPx,
|
|
6
6
|
getCssFilterFunctionPx,
|
|
7
|
-
getPropertyPanelVisibleSections,
|
|
8
7
|
inferBoxShadowPreset,
|
|
9
8
|
inferClipPathPreset,
|
|
10
|
-
isPropertyPanelMediaLikeSelection,
|
|
11
9
|
normalizePanelPxValue,
|
|
12
10
|
setCssFilterFunctionPx,
|
|
13
11
|
} from "./PropertyPanel";
|
|
@@ -66,51 +64,4 @@ describe("PropertyPanel style helpers", () => {
|
|
|
66
64
|
expect(buildStrokeStyleUpdates("none", "4px")).toEqual([["border-style", "none"]]);
|
|
67
65
|
expect(buildStrokeStyleUpdates("solid", "4px")).toEqual([["border-style", "solid"]]);
|
|
68
66
|
});
|
|
69
|
-
|
|
70
|
-
it("orders the simplified default inspector sections around high-confidence edits", () => {
|
|
71
|
-
expect(
|
|
72
|
-
getPropertyPanelVisibleSections({
|
|
73
|
-
hasSelection: true,
|
|
74
|
-
canEditStyles: true,
|
|
75
|
-
hasTextControls: true,
|
|
76
|
-
hasColorControls: true,
|
|
77
|
-
}),
|
|
78
|
-
).toEqual(["Text", "Layout", "Colors", "Radius", "Shadow"]);
|
|
79
|
-
|
|
80
|
-
expect(
|
|
81
|
-
getPropertyPanelVisibleSections({
|
|
82
|
-
hasSelection: true,
|
|
83
|
-
canEditStyles: true,
|
|
84
|
-
hasTextControls: false,
|
|
85
|
-
hasColorControls: false,
|
|
86
|
-
}),
|
|
87
|
-
).toEqual(["Layout", "Radius", "Shadow"]);
|
|
88
|
-
});
|
|
89
|
-
|
|
90
|
-
it("treats media tags and background-image layers as image-like controls", () => {
|
|
91
|
-
expect(
|
|
92
|
-
isPropertyPanelMediaLikeSelection({
|
|
93
|
-
tagName: "img",
|
|
94
|
-
styles: {},
|
|
95
|
-
}),
|
|
96
|
-
).toBe(true);
|
|
97
|
-
|
|
98
|
-
expect(
|
|
99
|
-
isPropertyPanelMediaLikeSelection({
|
|
100
|
-
tagName: "div",
|
|
101
|
-
styles: {
|
|
102
|
-
"background-image": "url(/assets/studio.png)",
|
|
103
|
-
},
|
|
104
|
-
}),
|
|
105
|
-
).toBe(true);
|
|
106
|
-
|
|
107
|
-
expect(
|
|
108
|
-
isPropertyPanelMediaLikeSelection({
|
|
109
|
-
tagName: "div",
|
|
110
|
-
styles: {
|
|
111
|
-
"background-image": "none",
|
|
112
|
-
},
|
|
113
|
-
}),
|
|
114
|
-
).toBe(false);
|
|
115
|
-
});
|
|
116
67
|
});
|
|
@@ -14,8 +14,14 @@ export interface RenderJob {
|
|
|
14
14
|
// Mirrors `CanvasResolution` from @hyperframes/core. Kept local because
|
|
15
15
|
// studio's tsconfig doesn't include node types, and the core barrel
|
|
16
16
|
// transitively pulls in modules with `node:fs` imports. Drift risk is
|
|
17
|
-
// low (
|
|
18
|
-
export type ResolutionPreset =
|
|
17
|
+
// low (6 string literals kept in sync manually with CANVAS_DIMENSIONS).
|
|
18
|
+
export type ResolutionPreset =
|
|
19
|
+
| "landscape"
|
|
20
|
+
| "portrait"
|
|
21
|
+
| "landscape-4k"
|
|
22
|
+
| "portrait-4k"
|
|
23
|
+
| "square"
|
|
24
|
+
| "square-4k";
|
|
19
25
|
|
|
20
26
|
export interface StartRenderOptions {
|
|
21
27
|
fps?: number;
|