hyperframes 0.7.59 → 0.7.60
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/cli.js +904 -115
- package/dist/hyperframe-runtime.js +23 -23
- package/dist/hyperframe.manifest.json +1 -1
- package/dist/hyperframe.runtime.iife.js +23 -23
- package/dist/hyperframes-player.global.js +1 -1
- package/dist/skills/hyperframes-cli/SKILL.md +1 -1
- package/dist/skills/hyperframes-cli/references/preview-render.md +11 -1
- package/dist/studio/assets/{hyperframes-player-Bm07FLkl.js → hyperframes-player-3XTTaVNf.js} +1 -1
- package/dist/studio/assets/{index-B995FG46.js → index-D6etaey-.js} +1 -1
- package/dist/studio/assets/index-DXbu6IPT.css +1 -0
- package/dist/studio/assets/{index-FvzmPhfG.js → index-Dh_WhagG.js} +1 -1
- package/dist/studio/assets/{index-CrkAdJkb.js → index-cH6NfVV_.js} +198 -198
- package/dist/studio/index.html +2 -2
- package/dist/studio/index.js +250 -108
- package/dist/studio/index.js.map +1 -1
- package/package.json +1 -1
- package/dist/studio/assets/index-Dj5p8U_A.css +0 -1
package/dist/studio/index.js
CHANGED
|
@@ -2915,6 +2915,7 @@ function FileManagerProvider({
|
|
|
2915
2915
|
readProjectFile,
|
|
2916
2916
|
writeProjectFile,
|
|
2917
2917
|
readOptionalProjectFile,
|
|
2918
|
+
observeProjectFileVersion,
|
|
2918
2919
|
updateEditingFileContent,
|
|
2919
2920
|
revealSourceOffset,
|
|
2920
2921
|
openSourceForSelection,
|
|
@@ -2951,6 +2952,7 @@ function FileManagerProvider({
|
|
|
2951
2952
|
readProjectFile,
|
|
2952
2953
|
writeProjectFile,
|
|
2953
2954
|
readOptionalProjectFile,
|
|
2955
|
+
observeProjectFileVersion,
|
|
2954
2956
|
updateEditingFileContent,
|
|
2955
2957
|
revealSourceOffset,
|
|
2956
2958
|
openSourceForSelection,
|
|
@@ -2984,6 +2986,7 @@ function FileManagerProvider({
|
|
|
2984
2986
|
readProjectFile,
|
|
2985
2987
|
writeProjectFile,
|
|
2986
2988
|
readOptionalProjectFile,
|
|
2989
|
+
observeProjectFileVersion,
|
|
2987
2990
|
updateEditingFileContent,
|
|
2988
2991
|
revealSourceOffset,
|
|
2989
2992
|
openSourceForSelection,
|
|
@@ -6920,6 +6923,20 @@ var StudioSaveNetworkError = class extends Error {
|
|
|
6920
6923
|
this.name = "StudioSaveNetworkError";
|
|
6921
6924
|
}
|
|
6922
6925
|
};
|
|
6926
|
+
var StudioFileConflictError = class extends StudioSaveHttpError {
|
|
6927
|
+
filePath;
|
|
6928
|
+
currentVersion;
|
|
6929
|
+
currentContent;
|
|
6930
|
+
attemptedContent;
|
|
6931
|
+
constructor(input) {
|
|
6932
|
+
super(`Save conflict: ${input.filePath} changed outside this Studio session`, 409);
|
|
6933
|
+
this.name = "StudioFileConflictError";
|
|
6934
|
+
this.filePath = input.filePath;
|
|
6935
|
+
this.currentVersion = input.currentVersion;
|
|
6936
|
+
this.currentContent = input.currentContent;
|
|
6937
|
+
this.attemptedContent = input.attemptedContent;
|
|
6938
|
+
}
|
|
6939
|
+
};
|
|
6923
6940
|
function readNumericProperty(value, key) {
|
|
6924
6941
|
const record = value;
|
|
6925
6942
|
const property = record[key];
|
|
@@ -7093,14 +7110,14 @@ async function saveProjectFilesWithHistory({
|
|
|
7093
7110
|
const writtenPaths = [];
|
|
7094
7111
|
try {
|
|
7095
7112
|
for (const path of changedPaths) {
|
|
7096
|
-
await writeFile(path, snapshots[path].after);
|
|
7113
|
+
await writeFile(path, snapshots[path].after, snapshots[path].before);
|
|
7097
7114
|
writtenPaths.push(path);
|
|
7098
7115
|
}
|
|
7099
7116
|
await recordEdit({ label, kind, coalesceKey, coalesceMs, files: snapshots });
|
|
7100
7117
|
} catch (error) {
|
|
7101
7118
|
try {
|
|
7102
7119
|
for (const path of writtenPaths.reverse()) {
|
|
7103
|
-
await writeFile(path, snapshots[path].before);
|
|
7120
|
+
await writeFile(path, snapshots[path].before, snapshots[path].after);
|
|
7104
7121
|
}
|
|
7105
7122
|
} catch (rollbackError) {
|
|
7106
7123
|
throw new AggregateError(
|
|
@@ -24480,11 +24497,11 @@ async function buildCandidateEdit(live, deps, mutate, sourceSnapshot) {
|
|
|
24480
24497
|
function isCutoverResult(value) {
|
|
24481
24498
|
return "status" in value;
|
|
24482
24499
|
}
|
|
24483
|
-
async function rollbackWrite(targetPath, originalContent, deps, cause) {
|
|
24500
|
+
async function rollbackWrite(targetPath, originalContent, expectedCurrentContent, deps, cause) {
|
|
24484
24501
|
try {
|
|
24485
24502
|
deps.domEditSaveTimestampRef.current = Date.now();
|
|
24486
24503
|
markSelfWrite(targetPath, originalContent);
|
|
24487
|
-
await deps.writeProjectFile(targetPath, originalContent);
|
|
24504
|
+
await deps.writeProjectFile(targetPath, originalContent, expectedCurrentContent);
|
|
24488
24505
|
return cause;
|
|
24489
24506
|
} catch (rollbackError) {
|
|
24490
24507
|
return new AggregateError(
|
|
@@ -24497,7 +24514,7 @@ async function writeAndRecord(after, targetPath, originalContent, deps, options)
|
|
|
24497
24514
|
deps.domEditSaveTimestampRef.current = Date.now();
|
|
24498
24515
|
markSelfWrite(targetPath, after);
|
|
24499
24516
|
try {
|
|
24500
|
-
await deps.writeProjectFile(targetPath, after);
|
|
24517
|
+
await deps.writeProjectFile(targetPath, after, originalContent);
|
|
24501
24518
|
} catch (error) {
|
|
24502
24519
|
return asCutoverError(error);
|
|
24503
24520
|
}
|
|
@@ -24511,7 +24528,7 @@ async function writeAndRecord(after, targetPath, originalContent, deps, options)
|
|
|
24511
24528
|
});
|
|
24512
24529
|
return null;
|
|
24513
24530
|
} catch (error) {
|
|
24514
|
-
return rollbackWrite(targetPath, originalContent, deps, asCutoverError(error));
|
|
24531
|
+
return rollbackWrite(targetPath, originalContent, after, deps, asCutoverError(error));
|
|
24515
24532
|
}
|
|
24516
24533
|
}
|
|
24517
24534
|
function refreshCommittedEdit(after, deps, options) {
|
|
@@ -36177,33 +36194,39 @@ function FlatSelectRow({
|
|
|
36177
36194
|
return /* @__PURE__ */ jsxs75("div", { className: "group flex min-h-[30px] items-center justify-between", children: [
|
|
36178
36195
|
/* @__PURE__ */ jsx88("span", { className: `text-[11px] ${VALUE_TIER_LABEL_CLASS[tier]}`, children: label }),
|
|
36179
36196
|
/* @__PURE__ */ jsxs75("span", { className: "flex items-center gap-2", children: [
|
|
36180
|
-
/* @__PURE__ */ jsxs75(
|
|
36181
|
-
|
|
36182
|
-
|
|
36183
|
-
{
|
|
36184
|
-
|
|
36185
|
-
|
|
36186
|
-
|
|
36187
|
-
|
|
36188
|
-
|
|
36189
|
-
|
|
36190
|
-
|
|
36191
|
-
|
|
36192
|
-
|
|
36193
|
-
|
|
36194
|
-
|
|
36195
|
-
|
|
36196
|
-
|
|
36197
|
-
|
|
36198
|
-
|
|
36199
|
-
|
|
36200
|
-
|
|
36201
|
-
|
|
36202
|
-
|
|
36203
|
-
|
|
36204
|
-
|
|
36205
|
-
|
|
36206
|
-
|
|
36197
|
+
/* @__PURE__ */ jsxs75(
|
|
36198
|
+
"label",
|
|
36199
|
+
{
|
|
36200
|
+
className: `flex items-center gap-1.5 border-b pb-px ${tier === "explicitCustom" ? "border-panel-accent/30 group-hover:border-panel-accent/70" : "border-panel-border-input/50 group-hover:border-panel-border-input"}`,
|
|
36201
|
+
children: [
|
|
36202
|
+
/* @__PURE__ */ jsx88(
|
|
36203
|
+
"select",
|
|
36204
|
+
{
|
|
36205
|
+
value,
|
|
36206
|
+
disabled,
|
|
36207
|
+
"aria-label": ariaLabel || label || void 0,
|
|
36208
|
+
onChange: (e) => {
|
|
36209
|
+
track("select", trackName);
|
|
36210
|
+
onChange(e.target.value);
|
|
36211
|
+
},
|
|
36212
|
+
className: `appearance-none bg-transparent text-right font-mono text-[11px] outline-none disabled:cursor-not-allowed ${VALUE_TIER_VALUE_CLASS[tier]}`,
|
|
36213
|
+
children: renderedOptions.map((option) => /* @__PURE__ */ jsx88("option", { value: option.value, children: option.label }, option.value))
|
|
36214
|
+
}
|
|
36215
|
+
),
|
|
36216
|
+
/* @__PURE__ */ jsx88(
|
|
36217
|
+
"svg",
|
|
36218
|
+
{
|
|
36219
|
+
width: "10",
|
|
36220
|
+
height: "10",
|
|
36221
|
+
viewBox: "0 0 10 10",
|
|
36222
|
+
fill: "currentColor",
|
|
36223
|
+
className: "flex-shrink-0 text-panel-text-5",
|
|
36224
|
+
children: /* @__PURE__ */ jsx88("path", { d: "M2 3l3 4 3-4z" })
|
|
36225
|
+
}
|
|
36226
|
+
)
|
|
36227
|
+
]
|
|
36228
|
+
}
|
|
36229
|
+
),
|
|
36207
36230
|
tier === "explicitCustom" && onReset && /* @__PURE__ */ jsx88(
|
|
36208
36231
|
"button",
|
|
36209
36232
|
{
|
|
@@ -36244,7 +36267,7 @@ function FlatRow({
|
|
|
36244
36267
|
"span",
|
|
36245
36268
|
{
|
|
36246
36269
|
"data-flat-row-value": "true",
|
|
36247
|
-
className: `min-w-0 border-b pb-px font-mono text-[11px] ${VALUE_TIER_VALUE_CLASS[tier]} ${tier === "explicitCustom" ? "border-
|
|
36270
|
+
className: `min-w-0 border-b pb-px font-mono text-[11px] ${VALUE_TIER_VALUE_CLASS[tier]} ${tier === "explicitCustom" ? "border-panel-accent/30 group-hover:border-panel-accent/70" : "border-panel-border-input/50 group-hover:border-panel-border-input"}`,
|
|
36248
36271
|
children: /* @__PURE__ */ jsx89(
|
|
36249
36272
|
CommitField,
|
|
36250
36273
|
{
|
|
@@ -36680,7 +36703,7 @@ function FlatTextFieldEditor({
|
|
|
36680
36703
|
children: "Weight"
|
|
36681
36704
|
}
|
|
36682
36705
|
),
|
|
36683
|
-
/* @__PURE__ */ jsxs77("label", { className: "flex items-center gap-1.5", children: [
|
|
36706
|
+
/* @__PURE__ */ jsxs77("label", { className: "flex items-center gap-1.5 border-b border-panel-border-input/50 pb-px hover:border-panel-border-input", children: [
|
|
36684
36707
|
/* @__PURE__ */ jsx90(
|
|
36685
36708
|
"select",
|
|
36686
36709
|
{
|
|
@@ -37912,7 +37935,7 @@ function FlatTimingRow({
|
|
|
37912
37935
|
};
|
|
37913
37936
|
const cell = (label, value, onCommit) => /* @__PURE__ */ jsxs82("div", { className: "grid gap-px", children: [
|
|
37914
37937
|
/* @__PURE__ */ jsx95("span", { className: "text-[9px] text-panel-text-4", children: label }),
|
|
37915
|
-
/* @__PURE__ */ jsx95("span", { className: "border-b border-
|
|
37938
|
+
/* @__PURE__ */ jsx95("span", { className: "border-b border-panel-border-input/50 font-mono text-[11px] text-panel-text-0 hover:border-panel-border-input", children: /* @__PURE__ */ jsx95(
|
|
37916
37939
|
CommitField,
|
|
37917
37940
|
{
|
|
37918
37941
|
value,
|
|
@@ -38724,7 +38747,7 @@ function FlatColorGradingSection({
|
|
|
38724
38747
|
track("select", "Custom LUT");
|
|
38725
38748
|
applyLut(src || null, src && lut?.src === src ? lut.intensity : 1);
|
|
38726
38749
|
},
|
|
38727
|
-
className: "bg-transparent font-mono text-[10px] text-panel-text-3 outline-none",
|
|
38750
|
+
className: "border-b border-panel-border-input/50 bg-transparent font-mono text-[10px] text-panel-text-3 outline-none hover:border-panel-border-input",
|
|
38728
38751
|
children: [
|
|
38729
38752
|
/* @__PURE__ */ jsx98("option", { value: "", children: "None" }),
|
|
38730
38753
|
lutAssets.map((asset) => /* @__PURE__ */ jsx98("option", { value: asset, children: asset.split("/").pop() ?? asset }, asset))
|
|
@@ -38876,7 +38899,7 @@ function FlatColorGradingSection({
|
|
|
38876
38899
|
onSetApplyScope(e.target.value);
|
|
38877
38900
|
},
|
|
38878
38901
|
disabled: applyBusy,
|
|
38879
|
-
className: "bg-transparent font-mono text-[11px] text-panel-text-0 outline-none disabled:opacity-50",
|
|
38902
|
+
className: "border-b border-panel-border-input/50 bg-transparent font-mono text-[11px] text-panel-text-0 outline-none hover:border-panel-border-input disabled:opacity-50",
|
|
38880
38903
|
children: [
|
|
38881
38904
|
/* @__PURE__ */ jsx98("option", { value: "source-file", children: "Current file media" }),
|
|
38882
38905
|
/* @__PURE__ */ jsx98("option", { value: "project", children: "All project media" })
|
|
@@ -40765,7 +40788,7 @@ var FileTree = memo33(function FileTree2({
|
|
|
40765
40788
|
});
|
|
40766
40789
|
|
|
40767
40790
|
// src/App.tsx
|
|
40768
|
-
import { useState as useState119, useCallback as useCallback141, useRef as useRef119, useMemo as
|
|
40791
|
+
import { useState as useState119, useCallback as useCallback141, useRef as useRef119, useMemo as useMemo50, useEffect as useEffect100, useLayoutEffect as useLayoutEffect4 } from "react";
|
|
40769
40792
|
|
|
40770
40793
|
// src/components/renders/useRenderQueue.ts
|
|
40771
40794
|
import { useState as useState64, useEffect as useEffect52, useCallback as useCallback58, useRef as useRef63, useMemo as useMemo31 } from "react";
|
|
@@ -42174,7 +42197,9 @@ function usePanelLayout(initialState2) {
|
|
|
42174
42197
|
const trackedSetRightPanelTab = useCallback62(
|
|
42175
42198
|
(tab) => {
|
|
42176
42199
|
if (tab === "design" || tab === "layers") {
|
|
42177
|
-
setRightInspectorPanes(
|
|
42200
|
+
setRightInspectorPanes(
|
|
42201
|
+
STUDIO_FLAT_INSPECTOR_ENABLED ? { design: tab === "design", layers: tab === "layers" } : (panes) => ({ ...panes, [tab]: true })
|
|
42202
|
+
);
|
|
42178
42203
|
}
|
|
42179
42204
|
setRightPanelTab(tab);
|
|
42180
42205
|
trackStudioEvent("tab_switch", { panel: "right_panel", tab });
|
|
@@ -42188,6 +42213,9 @@ function usePanelLayout(initialState2) {
|
|
|
42188
42213
|
return next;
|
|
42189
42214
|
});
|
|
42190
42215
|
}, []);
|
|
42216
|
+
const setExclusiveRightInspectorPane = useCallback62((pane) => {
|
|
42217
|
+
setRightInspectorPanes({ design: pane === "design", layers: pane === "layers" });
|
|
42218
|
+
}, []);
|
|
42191
42219
|
return {
|
|
42192
42220
|
leftWidth,
|
|
42193
42221
|
setLeftWidth,
|
|
@@ -42201,6 +42229,7 @@ function usePanelLayout(initialState2) {
|
|
|
42201
42229
|
setRightPanelTab: trackedSetRightPanelTab,
|
|
42202
42230
|
rightInspectorPanes,
|
|
42203
42231
|
toggleRightInspectorPane,
|
|
42232
|
+
setExclusiveRightInspectorPane,
|
|
42204
42233
|
toggleLeftSidebar,
|
|
42205
42234
|
handlePanelResizeStart,
|
|
42206
42235
|
handlePanelResizeMove,
|
|
@@ -42209,7 +42238,24 @@ function usePanelLayout(initialState2) {
|
|
|
42209
42238
|
}
|
|
42210
42239
|
|
|
42211
42240
|
// src/hooks/useFileManager.ts
|
|
42212
|
-
import { useState as useState70, useCallback as useCallback65, useRef as useRef71 } from "react";
|
|
42241
|
+
import { useState as useState70, useCallback as useCallback65, useMemo as useMemo34, useRef as useRef71 } from "react";
|
|
42242
|
+
|
|
42243
|
+
// src/utils/studioFileVersion.ts
|
|
42244
|
+
async function studioFileContentVersion(content) {
|
|
42245
|
+
const bytes = new TextEncoder().encode(content);
|
|
42246
|
+
const digest = await globalThis.crypto.subtle.digest("SHA-256", bytes);
|
|
42247
|
+
const hex = Array.from(new Uint8Array(digest), (byte) => byte.toString(16).padStart(2, "0")).join(
|
|
42248
|
+
""
|
|
42249
|
+
);
|
|
42250
|
+
return `"sha256:${hex}"`;
|
|
42251
|
+
}
|
|
42252
|
+
async function studioExpectedFileVersion(versions, path, expectedContent) {
|
|
42253
|
+
if (expectedContent !== void 0) return studioFileContentVersion(expectedContent);
|
|
42254
|
+
return versions.get(path);
|
|
42255
|
+
}
|
|
42256
|
+
function createStudioWriteToken() {
|
|
42257
|
+
return globalThis.crypto.randomUUID();
|
|
42258
|
+
}
|
|
42213
42259
|
|
|
42214
42260
|
// src/hooks/useFileTree.ts
|
|
42215
42261
|
import { useState as useState69, useCallback as useCallback63, useEffect as useEffect55, useMemo as useMemo33 } from "react";
|
|
@@ -42354,6 +42400,17 @@ function useFileManager({
|
|
|
42354
42400
|
const projectIdRef = useRef71(projectId);
|
|
42355
42401
|
projectIdRef.current = projectId;
|
|
42356
42402
|
const importedFontAssetsRef = useRef71([]);
|
|
42403
|
+
const fileVersionScope = useMemo34(
|
|
42404
|
+
() => ({ projectId, versions: /* @__PURE__ */ new Map() }),
|
|
42405
|
+
[projectId]
|
|
42406
|
+
);
|
|
42407
|
+
const fileVersions = fileVersionScope.versions;
|
|
42408
|
+
const observeProjectFileVersion = useCallback65(
|
|
42409
|
+
(path, version) => {
|
|
42410
|
+
fileVersions.set(path, version);
|
|
42411
|
+
},
|
|
42412
|
+
[fileVersions]
|
|
42413
|
+
);
|
|
42357
42414
|
const {
|
|
42358
42415
|
projectDir,
|
|
42359
42416
|
fileTree,
|
|
@@ -42373,14 +42430,35 @@ function useFileManager({
|
|
|
42373
42430
|
if (!response.ok) throw new Error(`Failed to read ${path}`);
|
|
42374
42431
|
const data = await response.json();
|
|
42375
42432
|
if (typeof data.content !== "string") throw new Error(`Missing file contents for ${path}`);
|
|
42433
|
+
fileVersions.set(path, data.version ?? response.headers.get("etag"));
|
|
42376
42434
|
return data.content;
|
|
42377
42435
|
},
|
|
42378
|
-
[projectId]
|
|
42436
|
+
[fileVersions, projectId]
|
|
42379
42437
|
);
|
|
42380
42438
|
const writeProjectFile = useCallback65(
|
|
42381
|
-
async (path, content) => {
|
|
42439
|
+
async (path, content, expectedContent) => {
|
|
42382
42440
|
if (!projectId) throw new Error("No active project");
|
|
42383
42441
|
const writeProjectId = projectId;
|
|
42442
|
+
let expectedVersion = await studioExpectedFileVersion(fileVersions, path, expectedContent);
|
|
42443
|
+
if (expectedVersion === void 0) {
|
|
42444
|
+
const preflight = await fetch(
|
|
42445
|
+
`/api/projects/${encodeURIComponent(writeProjectId)}/files/${encodeURIComponent(path)}`
|
|
42446
|
+
);
|
|
42447
|
+
if (preflight.ok) {
|
|
42448
|
+
const data = await preflight.json();
|
|
42449
|
+
throw new StudioFileConflictError({
|
|
42450
|
+
filePath: path,
|
|
42451
|
+
currentVersion: data.version ?? preflight.headers.get("etag"),
|
|
42452
|
+
currentContent: data.content ?? null,
|
|
42453
|
+
attemptedContent: content
|
|
42454
|
+
});
|
|
42455
|
+
} else if (preflight.status === 404) {
|
|
42456
|
+
expectedVersion = null;
|
|
42457
|
+
} else {
|
|
42458
|
+
throw await createStudioSaveHttpError(preflight, `Failed to read ${path} before save`);
|
|
42459
|
+
}
|
|
42460
|
+
}
|
|
42461
|
+
const writeToken = createStudioWriteToken();
|
|
42384
42462
|
await retryStudioSave(async () => {
|
|
42385
42463
|
let response;
|
|
42386
42464
|
try {
|
|
@@ -42388,7 +42466,11 @@ function useFileManager({
|
|
|
42388
42466
|
`/api/projects/${encodeURIComponent(writeProjectId)}/files/${encodeURIComponent(path)}`,
|
|
42389
42467
|
{
|
|
42390
42468
|
method: "PUT",
|
|
42391
|
-
headers: {
|
|
42469
|
+
headers: {
|
|
42470
|
+
"Content-Type": "text/plain",
|
|
42471
|
+
"X-Hyperframes-Write-Token": writeToken,
|
|
42472
|
+
...expectedVersion ? { "If-Match": expectedVersion } : { "If-None-Match": "*" }
|
|
42473
|
+
},
|
|
42392
42474
|
body: content
|
|
42393
42475
|
}
|
|
42394
42476
|
);
|
|
@@ -42397,13 +42479,32 @@ function useFileManager({
|
|
|
42397
42479
|
cause: error
|
|
42398
42480
|
});
|
|
42399
42481
|
}
|
|
42482
|
+
if (response.status === 409) {
|
|
42483
|
+
const conflict = await response.json().catch(() => null);
|
|
42484
|
+
const currentVersion = conflict?.currentVersion ?? null;
|
|
42485
|
+
if (currentVersion && conflict?.currentContent === content) {
|
|
42486
|
+
fileVersions.set(path, currentVersion);
|
|
42487
|
+
return;
|
|
42488
|
+
}
|
|
42489
|
+
throw new StudioFileConflictError({
|
|
42490
|
+
filePath: path,
|
|
42491
|
+
currentVersion,
|
|
42492
|
+
currentContent: conflict?.currentContent ?? null,
|
|
42493
|
+
attemptedContent: content
|
|
42494
|
+
});
|
|
42495
|
+
}
|
|
42400
42496
|
if (!response.ok) throw await createStudioSaveHttpError(response, `Failed to save ${path}`);
|
|
42497
|
+
const result = await response.json();
|
|
42498
|
+
const version = result.version ?? response.headers.get("etag");
|
|
42499
|
+
if (!version)
|
|
42500
|
+
throw new Error(`Save response for ${path} did not include a content version`);
|
|
42501
|
+
fileVersions.set(path, version);
|
|
42401
42502
|
});
|
|
42402
42503
|
if (projectIdRef.current === writeProjectId && editingPathRef.current === path) {
|
|
42403
42504
|
setEditingFile({ path, content });
|
|
42404
42505
|
}
|
|
42405
42506
|
},
|
|
42406
|
-
[projectId]
|
|
42507
|
+
[fileVersions, projectId]
|
|
42407
42508
|
);
|
|
42408
42509
|
const updateEditingFileContent = useCallback65((path, content) => {
|
|
42409
42510
|
if (editingPathRef.current === path) {
|
|
@@ -42418,9 +42519,10 @@ function useFileManager({
|
|
|
42418
42519
|
);
|
|
42419
42520
|
if (!response.ok) throw new Error(`Failed to read ${path}`);
|
|
42420
42521
|
const data = await response.json();
|
|
42522
|
+
fileVersions.set(path, data.version ?? response.headers.get("etag"));
|
|
42421
42523
|
return typeof data.content === "string" ? data.content : "";
|
|
42422
42524
|
},
|
|
42423
|
-
[projectId]
|
|
42525
|
+
[fileVersions, projectId]
|
|
42424
42526
|
);
|
|
42425
42527
|
const { saveRafRef, handleContentChange } = useEditorSave({
|
|
42426
42528
|
editingPathRef,
|
|
@@ -42450,13 +42552,14 @@ function useFileManager({
|
|
|
42450
42552
|
return r.json();
|
|
42451
42553
|
}).then((data) => {
|
|
42452
42554
|
if (data.content != null) {
|
|
42555
|
+
fileVersions.set(path, data.version ?? null);
|
|
42453
42556
|
setEditingFile({ path, content: data.content });
|
|
42454
42557
|
}
|
|
42455
42558
|
}).catch((err) => {
|
|
42456
42559
|
showToast(err instanceof Error ? err.message : `Failed to load ${path}`, "error");
|
|
42457
42560
|
});
|
|
42458
42561
|
},
|
|
42459
|
-
[showToast]
|
|
42562
|
+
[fileVersions, showToast]
|
|
42460
42563
|
);
|
|
42461
42564
|
const openSourceForSelection = useCallback65(
|
|
42462
42565
|
(sourceFile, target) => {
|
|
@@ -42477,6 +42580,7 @@ function useFileManager({
|
|
|
42477
42580
|
}).then((r) => r.json()).then((data) => {
|
|
42478
42581
|
if (requestId !== revealRequestIdRef.current) return;
|
|
42479
42582
|
if (data.content != null) {
|
|
42583
|
+
fileVersions.set(sourceFile, data.version ?? null);
|
|
42480
42584
|
setEditingFile({ path: sourceFile, content: data.content });
|
|
42481
42585
|
const match = findTagByTarget(data.content, target);
|
|
42482
42586
|
setRevealSourceOffset(match ? match.start : null);
|
|
@@ -42484,7 +42588,7 @@ function useFileManager({
|
|
|
42484
42588
|
}).catch(() => {
|
|
42485
42589
|
});
|
|
42486
42590
|
},
|
|
42487
|
-
[editingFile?.content]
|
|
42591
|
+
[editingFile?.content, fileVersions]
|
|
42488
42592
|
);
|
|
42489
42593
|
const uploadProjectFiles = useCallback65(
|
|
42490
42594
|
async (files, dir) => {
|
|
@@ -42689,6 +42793,7 @@ function useFileManager({
|
|
|
42689
42793
|
readProjectFile,
|
|
42690
42794
|
writeProjectFile,
|
|
42691
42795
|
readOptionalProjectFile,
|
|
42796
|
+
observeProjectFileVersion,
|
|
42692
42797
|
updateEditingFileContent,
|
|
42693
42798
|
// Click-to-source
|
|
42694
42799
|
revealSourceOffset,
|
|
@@ -42751,7 +42856,8 @@ function createDomEditSaveQueue(options = {}) {
|
|
|
42751
42856
|
return result;
|
|
42752
42857
|
} catch (error) {
|
|
42753
42858
|
consecutiveFailures += 1;
|
|
42754
|
-
if (consecutiveFailures >= failureThreshold)
|
|
42859
|
+
if (getStudioSaveStatusCode(error) === 409 || consecutiveFailures >= failureThreshold)
|
|
42860
|
+
open(error);
|
|
42755
42861
|
throw error;
|
|
42756
42862
|
}
|
|
42757
42863
|
};
|
|
@@ -42991,7 +43097,7 @@ function usePreviewPersistence({
|
|
|
42991
43097
|
if (!domEditSaveQueueRef.current) {
|
|
42992
43098
|
domEditSaveQueueRef.current = createDomEditSaveQueue({
|
|
42993
43099
|
onOpen: (event) => {
|
|
42994
|
-
const message = "Auto-save is paused. Check your connection.";
|
|
43100
|
+
const message = event.statusCode === 409 ? "Save paused: this file changed elsewhere. Reload and review the latest version before reapplying your edit." : "Auto-save is paused. Check your connection.";
|
|
42995
43101
|
setDomEditSaveQueuePaused(message);
|
|
42996
43102
|
showToastRef.current(message, "error");
|
|
42997
43103
|
trackStudioEvent("save_queue_paused", {
|
|
@@ -43136,7 +43242,10 @@ async function splitHtmlElement(projectId, targetPath, patchTarget, splitTime, n
|
|
|
43136
43242
|
}
|
|
43137
43243
|
);
|
|
43138
43244
|
if (!response.ok) throw new Error("Split request failed");
|
|
43139
|
-
|
|
43245
|
+
const data = await response.json();
|
|
43246
|
+
const version = data.version ?? response.headers.get("etag");
|
|
43247
|
+
if (!version) throw new Error("Split response did not include a content version");
|
|
43248
|
+
return { ...data, version };
|
|
43140
43249
|
}
|
|
43141
43250
|
async function splitGsapAnimations(projectId, targetPath, originalId, newId, splitTime, elementStart, elementDuration) {
|
|
43142
43251
|
const response = await fetch(
|
|
@@ -43164,6 +43273,7 @@ async function splitGsapAnimations(projectId, targetPath, originalId, newId, spl
|
|
|
43164
43273
|
const data = await response.json();
|
|
43165
43274
|
return {
|
|
43166
43275
|
content: data.ok && data.after ? data.after : null,
|
|
43276
|
+
version: data.version ?? response.headers.get("etag") ?? void 0,
|
|
43167
43277
|
skippedSelectors: data.skippedSelectors
|
|
43168
43278
|
};
|
|
43169
43279
|
}
|
|
@@ -43174,9 +43284,9 @@ function getOriginalContent(originals, path) {
|
|
|
43174
43284
|
}
|
|
43175
43285
|
return original;
|
|
43176
43286
|
}
|
|
43177
|
-
async function restoreFilesToOriginal(originals,
|
|
43178
|
-
for (const path of
|
|
43179
|
-
await writeProjectFile(path, getOriginalContent(originals, path));
|
|
43287
|
+
async function restoreFilesToOriginal(originals, snapshots, writeProjectFile) {
|
|
43288
|
+
for (const [path, snapshot] of snapshots) {
|
|
43289
|
+
await writeProjectFile(path, getOriginalContent(originals, path), snapshot.after);
|
|
43180
43290
|
}
|
|
43181
43291
|
}
|
|
43182
43292
|
async function readOriginalFiles(pid, elements, activeCompPath) {
|
|
@@ -43189,21 +43299,28 @@ async function readOriginalFiles(pid, elements, activeCompPath) {
|
|
|
43189
43299
|
}
|
|
43190
43300
|
return originals;
|
|
43191
43301
|
}
|
|
43192
|
-
async function splitElementsAtTime(pid, elements, splitTime, activeCompPath, originals, snapshots, writeProjectFile) {
|
|
43302
|
+
async function splitElementsAtTime(pid, elements, splitTime, activeCompPath, originals, snapshots, writeProjectFile, observeProjectFileVersion) {
|
|
43193
43303
|
let count = 0;
|
|
43194
43304
|
for (const element of elements) {
|
|
43195
|
-
const result = await executeSplit(
|
|
43305
|
+
const result = await executeSplit(
|
|
43306
|
+
pid,
|
|
43307
|
+
element,
|
|
43308
|
+
splitTime,
|
|
43309
|
+
activeCompPath,
|
|
43310
|
+
writeProjectFile,
|
|
43311
|
+
observeProjectFileVersion
|
|
43312
|
+
);
|
|
43196
43313
|
if (!result.changed) continue;
|
|
43197
43314
|
snapshots.set(result.targetPath, {
|
|
43198
43315
|
before: getOriginalContent(originals, result.targetPath),
|
|
43199
43316
|
after: result.patchedContent
|
|
43200
43317
|
});
|
|
43201
|
-
await writeProjectFile(result.targetPath, result.patchedContent);
|
|
43318
|
+
await writeProjectFile(result.targetPath, result.patchedContent, result.patchedContent);
|
|
43202
43319
|
count++;
|
|
43203
43320
|
}
|
|
43204
43321
|
return count;
|
|
43205
43322
|
}
|
|
43206
|
-
async function executeSplit(pid, element, splitTime, activeCompPath, writeProjectFile) {
|
|
43323
|
+
async function executeSplit(pid, element, splitTime, activeCompPath, writeProjectFile, observeProjectFileVersion) {
|
|
43207
43324
|
const patchTarget = buildPatchTarget(element);
|
|
43208
43325
|
if (!patchTarget) throw new Error("Clip is missing a patchable target.");
|
|
43209
43326
|
const targetPath = element.sourceFile || activeCompPath || "index.html";
|
|
@@ -43225,6 +43342,7 @@ async function executeSplit(pid, element, splitTime, activeCompPath, writeProjec
|
|
|
43225
43342
|
if (!splitResult.changed) {
|
|
43226
43343
|
return { targetPath, originalContent, patchedContent: originalContent, changed: false };
|
|
43227
43344
|
}
|
|
43345
|
+
observeProjectFileVersion?.(targetPath, splitResult.version);
|
|
43228
43346
|
let patchedContent = typeof splitResult.content === "string" ? splitResult.content : originalContent;
|
|
43229
43347
|
let skippedSelectors;
|
|
43230
43348
|
if (element.domId) {
|
|
@@ -43239,9 +43357,10 @@ async function executeSplit(pid, element, splitTime, activeCompPath, writeProjec
|
|
|
43239
43357
|
element.duration
|
|
43240
43358
|
);
|
|
43241
43359
|
if (gsapResult.content) patchedContent = gsapResult.content;
|
|
43360
|
+
if (gsapResult.version) observeProjectFileVersion?.(targetPath, gsapResult.version);
|
|
43242
43361
|
if (gsapResult.skippedSelectors?.length) skippedSelectors = gsapResult.skippedSelectors;
|
|
43243
43362
|
} catch (gsapError) {
|
|
43244
|
-
await writeProjectFile(targetPath, originalContent);
|
|
43363
|
+
await writeProjectFile(targetPath, originalContent, patchedContent);
|
|
43245
43364
|
throw gsapError;
|
|
43246
43365
|
}
|
|
43247
43366
|
}
|
|
@@ -43252,6 +43371,7 @@ function useRazorSplit({
|
|
|
43252
43371
|
activeCompPath,
|
|
43253
43372
|
showToast,
|
|
43254
43373
|
writeProjectFile,
|
|
43374
|
+
observeProjectFileVersion,
|
|
43255
43375
|
recordEdit,
|
|
43256
43376
|
domEditSaveTimestampRef,
|
|
43257
43377
|
reloadPreview,
|
|
@@ -43270,7 +43390,14 @@ function useRazorSplit({
|
|
|
43270
43390
|
const pid = projectIdRef.current;
|
|
43271
43391
|
if (!pid || !canSplitElementAt(element, splitTime)) return;
|
|
43272
43392
|
try {
|
|
43273
|
-
const { targetPath, originalContent, patchedContent, changed, skippedSelectors } = await executeSplit(
|
|
43393
|
+
const { targetPath, originalContent, patchedContent, changed, skippedSelectors } = await executeSplit(
|
|
43394
|
+
pid,
|
|
43395
|
+
element,
|
|
43396
|
+
splitTime,
|
|
43397
|
+
activeCompPath,
|
|
43398
|
+
writeProjectFile,
|
|
43399
|
+
observeProjectFileVersion
|
|
43400
|
+
);
|
|
43274
43401
|
if (!changed) {
|
|
43275
43402
|
showToast("Failed to split clip \u2014 playhead may be outside the clip", "error");
|
|
43276
43403
|
return;
|
|
@@ -43305,6 +43432,7 @@ function useRazorSplit({
|
|
|
43305
43432
|
recordEdit,
|
|
43306
43433
|
showToast,
|
|
43307
43434
|
writeProjectFile,
|
|
43435
|
+
observeProjectFileVersion,
|
|
43308
43436
|
domEditSaveTimestampRef,
|
|
43309
43437
|
reloadPreview,
|
|
43310
43438
|
forceReloadSdkSession,
|
|
@@ -43312,6 +43440,7 @@ function useRazorSplit({
|
|
|
43312
43440
|
]
|
|
43313
43441
|
);
|
|
43314
43442
|
const handleRazorSplitAll = useCallback68(
|
|
43443
|
+
// fallow-ignore-next-line complexity
|
|
43315
43444
|
async (splitTime) => {
|
|
43316
43445
|
if (isRecordingRef?.current) {
|
|
43317
43446
|
showToast("Cannot edit timeline while recording", "error");
|
|
@@ -43333,7 +43462,8 @@ function useRazorSplit({
|
|
|
43333
43462
|
activeCompPath,
|
|
43334
43463
|
originals,
|
|
43335
43464
|
finalSnapshots,
|
|
43336
|
-
writeProjectFile
|
|
43465
|
+
writeProjectFile,
|
|
43466
|
+
observeProjectFileVersion
|
|
43337
43467
|
);
|
|
43338
43468
|
if (splitCount === 0) return;
|
|
43339
43469
|
domEditSaveTimestampRef.current = Date.now();
|
|
@@ -43348,7 +43478,7 @@ function useRazorSplit({
|
|
|
43348
43478
|
showToast(`Split ${splitCount} clips at ${splitTime.toFixed(2)}s`, "info");
|
|
43349
43479
|
} catch (error) {
|
|
43350
43480
|
try {
|
|
43351
|
-
await restoreFilesToOriginal(originals, finalSnapshots
|
|
43481
|
+
await restoreFilesToOriginal(originals, finalSnapshots, writeProjectFile);
|
|
43352
43482
|
} catch {
|
|
43353
43483
|
}
|
|
43354
43484
|
const message = error instanceof Error ? error.message : "Failed to split clips";
|
|
@@ -43360,6 +43490,7 @@ function useRazorSplit({
|
|
|
43360
43490
|
recordEdit,
|
|
43361
43491
|
showToast,
|
|
43362
43492
|
writeProjectFile,
|
|
43493
|
+
observeProjectFileVersion,
|
|
43363
43494
|
domEditSaveTimestampRef,
|
|
43364
43495
|
reloadPreview,
|
|
43365
43496
|
forceReloadSdkSession,
|
|
@@ -44059,6 +44190,7 @@ function useTimelineEditing({
|
|
|
44059
44190
|
timelineElements,
|
|
44060
44191
|
showToast,
|
|
44061
44192
|
writeProjectFile,
|
|
44193
|
+
observeProjectFileVersion,
|
|
44062
44194
|
recordEdit,
|
|
44063
44195
|
domEditSaveTimestampRef,
|
|
44064
44196
|
reloadPreview,
|
|
@@ -44440,6 +44572,7 @@ function useTimelineEditing({
|
|
|
44440
44572
|
activeCompPath,
|
|
44441
44573
|
showToast,
|
|
44442
44574
|
writeProjectFile,
|
|
44575
|
+
observeProjectFileVersion,
|
|
44443
44576
|
recordEdit,
|
|
44444
44577
|
domEditSaveTimestampRef,
|
|
44445
44578
|
reloadPreview,
|
|
@@ -46576,7 +46709,7 @@ function useDomEditCommits({
|
|
|
46576
46709
|
const preparedContent = options.prepareContent(patchedContent, targetPath);
|
|
46577
46710
|
if (preparedContent !== patchedContent) {
|
|
46578
46711
|
try {
|
|
46579
|
-
await writeProjectFile(targetPath, preparedContent);
|
|
46712
|
+
await writeProjectFile(targetPath, preparedContent, patchedContent);
|
|
46580
46713
|
finalContent = preparedContent;
|
|
46581
46714
|
} catch (error) {
|
|
46582
46715
|
showToast(
|
|
@@ -46854,7 +46987,7 @@ function useGroupCommits(params) {
|
|
|
46854
46987
|
}
|
|
46855
46988
|
|
|
46856
46989
|
// src/hooks/useGsapScriptCommits.ts
|
|
46857
|
-
import { useCallback as useCallback87, useMemo as
|
|
46990
|
+
import { useCallback as useCallback87, useMemo as useMemo35, useRef as useRef83 } from "react";
|
|
46858
46991
|
import { findUnsafeMutationValues } from "@hyperframes/core/studio-api/finite-mutation";
|
|
46859
46992
|
|
|
46860
46993
|
// src/hooks/gsapRuntimePatch.ts
|
|
@@ -48101,7 +48234,7 @@ function useGsapScriptCommits({ projectIdRef, activeCompPath, previewIframeRef,
|
|
|
48101
48234
|
if (!result) return;
|
|
48102
48235
|
await finalizeSuccessfulMutation(pid, compositionPath, last.selection, last.mutation, targetPath, result, options);
|
|
48103
48236
|
}, [showToast, finalizeSuccessfulMutation]);
|
|
48104
|
-
const commitMutation =
|
|
48237
|
+
const commitMutation = useMemo35(() => {
|
|
48105
48238
|
const serializeFile = (file, task) => {
|
|
48106
48239
|
if (writeProjectFile) {
|
|
48107
48240
|
return serializeStudioFileMutation(writeProjectFile, file, task);
|
|
@@ -48166,7 +48299,7 @@ function useGsapScriptCommits({ projectIdRef, activeCompPath, previewIframeRef,
|
|
|
48166
48299
|
},
|
|
48167
48300
|
[activeProjectId]
|
|
48168
48301
|
);
|
|
48169
|
-
const sdkDeps =
|
|
48302
|
+
const sdkDeps = useMemo35(
|
|
48170
48303
|
() => writeProjectFile ? {
|
|
48171
48304
|
editHistory: { recordEdit: editHistory.recordEdit },
|
|
48172
48305
|
writeProjectFile,
|
|
@@ -50426,7 +50559,7 @@ function useStudioSdkSessions(projectId, activeCompPath, domEditSaveTimestampRef
|
|
|
50426
50559
|
}
|
|
50427
50560
|
|
|
50428
50561
|
// src/hooks/useBlockHandlers.ts
|
|
50429
|
-
import { useCallback as useCallback96, useMemo as
|
|
50562
|
+
import { useCallback as useCallback96, useMemo as useMemo36, useRef as useRef89, useState as useState76 } from "react";
|
|
50430
50563
|
|
|
50431
50564
|
// src/utils/blockInstaller.ts
|
|
50432
50565
|
function getMaxZIndexFromIframe(iframe) {
|
|
@@ -50565,7 +50698,7 @@ function useBlockHandlers({
|
|
|
50565
50698
|
setRightPanelTab
|
|
50566
50699
|
}) {
|
|
50567
50700
|
const [activeBlockParams, setActiveBlockParams] = useState76(null);
|
|
50568
|
-
const blockCtx =
|
|
50701
|
+
const blockCtx = useMemo36(
|
|
50569
50702
|
() => ({
|
|
50570
50703
|
activeCompPath: blockCtxDeps.activeCompPath,
|
|
50571
50704
|
timelineElements: blockCtxDeps.timelineElements,
|
|
@@ -52255,7 +52388,7 @@ function useFrameCapture({
|
|
|
52255
52388
|
}
|
|
52256
52389
|
|
|
52257
52390
|
// src/hooks/useLintModal.ts
|
|
52258
|
-
import { useState as useState81, useCallback as useCallback104, useEffect as useEffect71, useRef as useRef96, useMemo as
|
|
52391
|
+
import { useState as useState81, useCallback as useCallback104, useEffect as useEffect71, useRef as useRef96, useMemo as useMemo37 } from "react";
|
|
52259
52392
|
function parseFinding(f) {
|
|
52260
52393
|
return {
|
|
52261
52394
|
severity: f.severity === "error" ? "error" : "warning",
|
|
@@ -52327,8 +52460,8 @@ function useLintModal(projectId, refreshKey) {
|
|
|
52327
52460
|
},
|
|
52328
52461
|
[backgroundFindings]
|
|
52329
52462
|
);
|
|
52330
|
-
const findingsByElement =
|
|
52331
|
-
const findingsByFile =
|
|
52463
|
+
const findingsByElement = useMemo37(() => groupFindings((f) => f.elementId), [groupFindings]);
|
|
52464
|
+
const findingsByFile = useMemo37(() => groupFindings((f) => f.file), [groupFindings]);
|
|
52332
52465
|
useEffect71(() => {
|
|
52333
52466
|
usePlayerStore.getState().setLintFindingsByElement(findingsByElement);
|
|
52334
52467
|
}, [findingsByElement]);
|
|
@@ -52687,7 +52820,7 @@ function useStudioUrlState({
|
|
|
52687
52820
|
}
|
|
52688
52821
|
|
|
52689
52822
|
// src/hooks/useStudioContextValue.ts
|
|
52690
|
-
import { useCallback as useCallback108, useMemo as
|
|
52823
|
+
import { useCallback as useCallback108, useMemo as useMemo38, useRef as useRef99, useState as useState84 } from "react";
|
|
52691
52824
|
function buildStudioContextValue(input) {
|
|
52692
52825
|
return {
|
|
52693
52826
|
projectId: input.projectId,
|
|
@@ -52712,7 +52845,7 @@ function buildStudioContextValue(input) {
|
|
|
52712
52845
|
};
|
|
52713
52846
|
}
|
|
52714
52847
|
function useInspectorState(rightPanelTab, rightInspectorPanes, rightCollapsed, isPlaying, isGestureRecording) {
|
|
52715
|
-
return
|
|
52848
|
+
return useMemo38(() => {
|
|
52716
52849
|
const inspectorTabActive = rightPanelTab === "design" || rightPanelTab === "layers";
|
|
52717
52850
|
const layersPanelActive = STUDIO_INSPECTOR_PANELS_ENABLED && inspectorTabActive && rightInspectorPanes.layers;
|
|
52718
52851
|
const designPanelActive = STUDIO_INSPECTOR_PANELS_ENABLED && inspectorTabActive && rightInspectorPanes.design;
|
|
@@ -52774,7 +52907,7 @@ function useGlobalFileDrop(handleTimelineFileDrop) {
|
|
|
52774
52907
|
import { useRef as useRef100 } from "react";
|
|
52775
52908
|
|
|
52776
52909
|
// src/contexts/PanelLayoutContext.tsx
|
|
52777
|
-
import { createContext as createContext8, useContext as useContext8, useMemo as
|
|
52910
|
+
import { createContext as createContext8, useContext as useContext8, useMemo as useMemo39 } from "react";
|
|
52778
52911
|
import { jsx as jsx114 } from "react/jsx-runtime";
|
|
52779
52912
|
var PanelLayoutContext = createContext8(null);
|
|
52780
52913
|
function usePanelLayoutContext() {
|
|
@@ -52796,6 +52929,7 @@ function PanelLayoutProvider({
|
|
|
52796
52929
|
setRightPanelTab,
|
|
52797
52930
|
rightInspectorPanes,
|
|
52798
52931
|
toggleRightInspectorPane,
|
|
52932
|
+
setExclusiveRightInspectorPane,
|
|
52799
52933
|
toggleLeftSidebar,
|
|
52800
52934
|
handlePanelResizeStart,
|
|
52801
52935
|
handlePanelResizeMove,
|
|
@@ -52803,7 +52937,7 @@ function PanelLayoutProvider({
|
|
|
52803
52937
|
},
|
|
52804
52938
|
children
|
|
52805
52939
|
}) {
|
|
52806
|
-
const stable =
|
|
52940
|
+
const stable = useMemo39(
|
|
52807
52941
|
() => ({
|
|
52808
52942
|
leftWidth,
|
|
52809
52943
|
setLeftWidth,
|
|
@@ -52817,6 +52951,7 @@ function PanelLayoutProvider({
|
|
|
52817
52951
|
setRightPanelTab,
|
|
52818
52952
|
rightInspectorPanes,
|
|
52819
52953
|
toggleRightInspectorPane,
|
|
52954
|
+
setExclusiveRightInspectorPane,
|
|
52820
52955
|
toggleLeftSidebar,
|
|
52821
52956
|
handlePanelResizeStart,
|
|
52822
52957
|
handlePanelResizeMove,
|
|
@@ -52835,6 +52970,7 @@ function PanelLayoutProvider({
|
|
|
52835
52970
|
setRightPanelTab,
|
|
52836
52971
|
rightInspectorPanes,
|
|
52837
52972
|
toggleRightInspectorPane,
|
|
52973
|
+
setExclusiveRightInspectorPane,
|
|
52838
52974
|
toggleLeftSidebar,
|
|
52839
52975
|
handlePanelResizeStart,
|
|
52840
52976
|
handlePanelResizeMove,
|
|
@@ -52850,7 +52986,7 @@ import {
|
|
|
52850
52986
|
useCallback as useCallback109,
|
|
52851
52987
|
useContext as useContext9,
|
|
52852
52988
|
useEffect as useEffect73,
|
|
52853
|
-
useMemo as
|
|
52989
|
+
useMemo as useMemo40,
|
|
52854
52990
|
useState as useState85
|
|
52855
52991
|
} from "react";
|
|
52856
52992
|
import { jsx as jsx115 } from "react/jsx-runtime";
|
|
@@ -52880,7 +53016,7 @@ function useViewModeState() {
|
|
|
52880
53016
|
setMode(mode);
|
|
52881
53017
|
writeViewModeToUrl(mode);
|
|
52882
53018
|
}, []);
|
|
52883
|
-
return
|
|
53019
|
+
return useMemo40(() => ({ viewMode, setViewMode }), [viewMode, setViewMode]);
|
|
52884
53020
|
}
|
|
52885
53021
|
var ViewModeContext = createContext9(null);
|
|
52886
53022
|
function useViewMode() {
|
|
@@ -54056,7 +54192,7 @@ function useGestureCommit({
|
|
|
54056
54192
|
}
|
|
54057
54193
|
|
|
54058
54194
|
// src/components/editor/GestureTrailOverlay.tsx
|
|
54059
|
-
import { memo as memo36, useMemo as
|
|
54195
|
+
import { memo as memo36, useMemo as useMemo41 } from "react";
|
|
54060
54196
|
import { Fragment as Fragment36, jsx as jsx117, jsxs as jsxs101 } from "react/jsx-runtime";
|
|
54061
54197
|
var GestureTrailOverlay = memo36(function GestureTrailOverlay2({
|
|
54062
54198
|
samples,
|
|
@@ -54068,7 +54204,7 @@ var GestureTrailOverlay = memo36(function GestureTrailOverlay2({
|
|
|
54068
54204
|
mode,
|
|
54069
54205
|
accentColor = "#3CE6AC"
|
|
54070
54206
|
}) {
|
|
54071
|
-
const trailPoints =
|
|
54207
|
+
const trailPoints = useMemo41(() => {
|
|
54072
54208
|
if (!canvasRect) return "";
|
|
54073
54209
|
if (trail && trail.length > 1) {
|
|
54074
54210
|
return trail.map((p) => `${p.x - canvasRect.left},${p.y - canvasRect.top}`).join(" ");
|
|
@@ -54076,7 +54212,7 @@ var GestureTrailOverlay = memo36(function GestureTrailOverlay2({
|
|
|
54076
54212
|
if (samples.length === 0) return "";
|
|
54077
54213
|
return samples.filter((s) => s.properties.x != null && s.properties.y != null).map((s) => `${s.properties.x},${s.properties.y}`).join(" ");
|
|
54078
54214
|
}, [samples, trail, sampleCount, canvasRect?.left, canvasRect?.top]);
|
|
54079
|
-
const simplifiedPath =
|
|
54215
|
+
const simplifiedPath = useMemo41(() => {
|
|
54080
54216
|
if (!simplifiedPoints || simplifiedPoints.size === 0) return "";
|
|
54081
54217
|
const pts = [];
|
|
54082
54218
|
for (const [pct, props] of simplifiedPoints) {
|
|
@@ -54088,7 +54224,7 @@ var GestureTrailOverlay = memo36(function GestureTrailOverlay2({
|
|
|
54088
54224
|
if (pts.length === 0) return "";
|
|
54089
54225
|
return pts.map((p) => `${p.x},${p.y}`).join(" ");
|
|
54090
54226
|
}, [simplifiedPoints]);
|
|
54091
|
-
const diamondPositions =
|
|
54227
|
+
const diamondPositions = useMemo41(() => {
|
|
54092
54228
|
if (!simplifiedPoints || simplifiedPoints.size === 0) return [];
|
|
54093
54229
|
const pts = [];
|
|
54094
54230
|
for (const [pct, props] of simplifiedPoints) {
|
|
@@ -54411,7 +54547,7 @@ var CompositionsTab = memo37(function CompositionsTab2({
|
|
|
54411
54547
|
});
|
|
54412
54548
|
|
|
54413
54549
|
// src/components/sidebar/AssetsTab.tsx
|
|
54414
|
-
import { memo as memo38, useState as useState93, useCallback as useCallback115, useRef as useRef106, useMemo as
|
|
54550
|
+
import { memo as memo38, useState as useState93, useCallback as useCallback115, useRef as useRef106, useMemo as useMemo43, useEffect as useEffect81 } from "react";
|
|
54415
54551
|
|
|
54416
54552
|
// src/components/sidebar/assetHelpers.ts
|
|
54417
54553
|
function getCategory(path) {
|
|
@@ -54781,7 +54917,7 @@ function AudioRow({
|
|
|
54781
54917
|
}
|
|
54782
54918
|
|
|
54783
54919
|
// src/components/sidebar/GlobalAssetsView.tsx
|
|
54784
|
-
import { useEffect as useEffect78, useMemo as
|
|
54920
|
+
import { useEffect as useEffect78, useMemo as useMemo42, useState as useState90 } from "react";
|
|
54785
54921
|
import { jsx as jsx121, jsxs as jsxs105 } from "react/jsx-runtime";
|
|
54786
54922
|
function globalAssetRows(records, query = "") {
|
|
54787
54923
|
const q = query.trim().toLowerCase();
|
|
@@ -54808,7 +54944,7 @@ function GlobalAssetsView({ searchQuery }) {
|
|
|
54808
54944
|
cancelled = true;
|
|
54809
54945
|
};
|
|
54810
54946
|
}, []);
|
|
54811
|
-
const rows =
|
|
54947
|
+
const rows = useMemo42(() => globalAssetRows(records ?? [], searchQuery), [records, searchQuery]);
|
|
54812
54948
|
if (records === null) {
|
|
54813
54949
|
return /* @__PURE__ */ jsx121("p", { className: "px-4 py-3 text-[11px] text-panel-text-5", children: "Loading global assets\u2026" });
|
|
54814
54950
|
}
|
|
@@ -55220,8 +55356,8 @@ var AssetsTab = memo38(function AssetsTab2({
|
|
|
55220
55356
|
}
|
|
55221
55357
|
}, []);
|
|
55222
55358
|
const elements = usePlayerStore((s) => s.elements);
|
|
55223
|
-
const usedPaths =
|
|
55224
|
-
const mediaAssets =
|
|
55359
|
+
const usedPaths = useMemo43(() => deriveUsedPaths(elements), [elements]);
|
|
55360
|
+
const mediaAssets = useMemo43(() => {
|
|
55225
55361
|
const media = assets.filter((a) => MEDIA_EXT.test(a) || FONT_EXT.test(a));
|
|
55226
55362
|
const all = filterByUsage(media, usedPaths, usageFilter);
|
|
55227
55363
|
if (!searchQuery) return all;
|
|
@@ -55233,7 +55369,7 @@ var AssetsTab = memo38(function AssetsTab2({
|
|
|
55233
55369
|
return rec?.description?.toLowerCase().includes(q);
|
|
55234
55370
|
});
|
|
55235
55371
|
}, [assets, searchQuery, manifest, usageFilter, usedPaths]);
|
|
55236
|
-
const categorized =
|
|
55372
|
+
const categorized = useMemo43(() => {
|
|
55237
55373
|
const groups = { audio: [], images: [], video: [], fonts: [] };
|
|
55238
55374
|
for (const a of mediaAssets) {
|
|
55239
55375
|
const cat = getCategory(a);
|
|
@@ -55248,12 +55384,12 @@ var AssetsTab = memo38(function AssetsTab2({
|
|
|
55248
55384
|
}
|
|
55249
55385
|
return groups;
|
|
55250
55386
|
}, [mediaAssets, usedPaths]);
|
|
55251
|
-
const counts =
|
|
55387
|
+
const counts = useMemo43(() => {
|
|
55252
55388
|
const c = { all: mediaAssets.length };
|
|
55253
55389
|
for (const cat of FILTER_ORDER) c[cat] = categorized[cat].length;
|
|
55254
55390
|
return c;
|
|
55255
55391
|
}, [mediaAssets, categorized]);
|
|
55256
|
-
const usageCounts =
|
|
55392
|
+
const usageCounts = useMemo43(
|
|
55257
55393
|
() => countUsage(
|
|
55258
55394
|
assets.filter((a) => MEDIA_EXT.test(a) || FONT_EXT.test(a)),
|
|
55259
55395
|
usedPaths
|
|
@@ -55500,7 +55636,7 @@ import { memo as memo39, useState as useState95, useCallback as useCallback116,
|
|
|
55500
55636
|
import { createPortal as createPortal7 } from "react-dom";
|
|
55501
55637
|
|
|
55502
55638
|
// src/hooks/useBlockCatalog.ts
|
|
55503
|
-
import { useState as useState94, useEffect as useEffect82, useMemo as
|
|
55639
|
+
import { useState as useState94, useEffect as useEffect82, useMemo as useMemo44 } from "react";
|
|
55504
55640
|
|
|
55505
55641
|
// src/utils/blockCategories.ts
|
|
55506
55642
|
import {
|
|
@@ -55554,7 +55690,7 @@ function useBlockCatalog() {
|
|
|
55554
55690
|
cancelled = true;
|
|
55555
55691
|
};
|
|
55556
55692
|
}, []);
|
|
55557
|
-
const filteredBlocks =
|
|
55693
|
+
const filteredBlocks = useMemo44(() => {
|
|
55558
55694
|
let result = blocks;
|
|
55559
55695
|
if (category) {
|
|
55560
55696
|
result = result.filter((b) => b.category === category);
|
|
@@ -56564,7 +56700,7 @@ function StudioLeftSidebar({
|
|
|
56564
56700
|
}
|
|
56565
56701
|
|
|
56566
56702
|
// src/components/StudioRightPanel.tsx
|
|
56567
|
-
import { useCallback as useCallback134, useEffect as useEffect89, useMemo as
|
|
56703
|
+
import { useCallback as useCallback134, useEffect as useEffect89, useMemo as useMemo46, useRef as useRef114 } from "react";
|
|
56568
56704
|
|
|
56569
56705
|
// src/components/editor/LayersPanel.tsx
|
|
56570
56706
|
import { memo as memo41, useState as useState99, useCallback as useCallback120, useEffect as useEffect84, useRef as useRef110 } from "react";
|
|
@@ -59241,7 +59377,7 @@ function SlideshowPanel({ scenes, onPersist, onPersistNotes }) {
|
|
|
59241
59377
|
}
|
|
59242
59378
|
|
|
59243
59379
|
// src/components/panels/VariablesPanel.tsx
|
|
59244
|
-
import { memo as memo47, useCallback as useCallback130, useEffect as useEffect88, useMemo as
|
|
59380
|
+
import { memo as memo47, useCallback as useCallback130, useEffect as useEffect88, useMemo as useMemo45, useState as useState109 } from "react";
|
|
59245
59381
|
|
|
59246
59382
|
// src/hooks/useVariablesPersist.ts
|
|
59247
59383
|
import { useCallback as useCallback127 } from "react";
|
|
@@ -59945,22 +60081,22 @@ var VariablesPanel = memo47(function VariablesPanel2({
|
|
|
59945
60081
|
domEditSaveTimestampRef,
|
|
59946
60082
|
publishSdkSession
|
|
59947
60083
|
});
|
|
59948
|
-
const declarations =
|
|
60084
|
+
const declarations = useMemo45(
|
|
59949
60085
|
() => sdkSession?.getVariableDeclarations() ?? [],
|
|
59950
60086
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
59951
60087
|
[sdkSession, refreshKey, revision]
|
|
59952
60088
|
);
|
|
59953
|
-
const usage =
|
|
60089
|
+
const usage = useMemo45(
|
|
59954
60090
|
() => sdkSession?.getVariableUsage() ?? null,
|
|
59955
60091
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
59956
60092
|
[sdkSession, refreshKey, revision]
|
|
59957
60093
|
);
|
|
59958
|
-
const issues =
|
|
60094
|
+
const issues = useMemo45(
|
|
59959
60095
|
() => previewValues && sdkSession ? sdkSession.validateVariableValues(previewValues) : [],
|
|
59960
60096
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
59961
60097
|
[sdkSession, previewValues, refreshKey, revision]
|
|
59962
60098
|
);
|
|
59963
|
-
const effectiveValues =
|
|
60099
|
+
const effectiveValues = useMemo45(
|
|
59964
60100
|
() => sdkSession?.getVariableValues(previewValues ?? void 0) ?? {},
|
|
59965
60101
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
59966
60102
|
[sdkSession, previewValues, refreshKey, revision]
|
|
@@ -60617,6 +60753,7 @@ function StudioRightPanel({
|
|
|
60617
60753
|
setRightPanelTab,
|
|
60618
60754
|
rightInspectorPanes,
|
|
60619
60755
|
toggleRightInspectorPane,
|
|
60756
|
+
setExclusiveRightInspectorPane,
|
|
60620
60757
|
handlePanelResizeStart,
|
|
60621
60758
|
handlePanelResizeMove,
|
|
60622
60759
|
handlePanelResizeEnd
|
|
@@ -60722,7 +60859,7 @@ function StudioRightPanel({
|
|
|
60722
60859
|
);
|
|
60723
60860
|
const renderJobs = renderQueue.jobs;
|
|
60724
60861
|
const inspectorTabActive = rightPanelTab === "design" || rightPanelTab === "layers";
|
|
60725
|
-
const slideshowScenes =
|
|
60862
|
+
const slideshowScenes = useMemo46(() => {
|
|
60726
60863
|
try {
|
|
60727
60864
|
const win = previewIframeRef.current?.contentWindow;
|
|
60728
60865
|
return (win?.__clipManifest?.scenes ?? []).map((s) => ({
|
|
@@ -60742,6 +60879,10 @@ function StudioRightPanel({
|
|
|
60742
60879
|
setRightPanelTab(pane);
|
|
60743
60880
|
return;
|
|
60744
60881
|
}
|
|
60882
|
+
if (STUDIO_FLAT_INSPECTOR_ENABLED) {
|
|
60883
|
+
setExclusiveRightInspectorPane(pane);
|
|
60884
|
+
return;
|
|
60885
|
+
}
|
|
60745
60886
|
toggleRightInspectorPane(pane);
|
|
60746
60887
|
};
|
|
60747
60888
|
const handleApplyColorGradingScope = useCallback134(
|
|
@@ -61033,7 +61174,7 @@ function StudioRightPanel({
|
|
|
61033
61174
|
domEditSaveTimestampRef,
|
|
61034
61175
|
recordEdit
|
|
61035
61176
|
}
|
|
61036
|
-
) : layersPaneOpen && designPaneOpen ? /* @__PURE__ */ jsxs124("div", { ref: splitContainerRef, className: "flex h-full min-h-0 min-w-0 flex-col", children: [
|
|
61177
|
+
) : layersPaneOpen && designPaneOpen && !STUDIO_FLAT_INSPECTOR_ENABLED ? /* @__PURE__ */ jsxs124("div", { ref: splitContainerRef, className: "flex h-full min-h-0 min-w-0 flex-col", children: [
|
|
61037
61178
|
/* @__PURE__ */ jsx144(
|
|
61038
61179
|
"div",
|
|
61039
61180
|
{
|
|
@@ -61856,7 +61997,7 @@ function useProjectSignaturePoll(projectId, currentSignature, onChange) {
|
|
|
61856
61997
|
}
|
|
61857
61998
|
|
|
61858
61999
|
// src/components/storyboard/StoryboardLoaded.tsx
|
|
61859
|
-
import { useEffect as useEffect98, useMemo as
|
|
62000
|
+
import { useEffect as useEffect98, useMemo as useMemo49, useState as useState116 } from "react";
|
|
61860
62001
|
|
|
61861
62002
|
// src/components/storyboard/StoryboardDirection.tsx
|
|
61862
62003
|
import { jsx as jsx146, jsxs as jsxs126 } from "react/jsx-runtime";
|
|
@@ -62106,7 +62247,7 @@ function StoryboardScriptPanel({ script }) {
|
|
|
62106
62247
|
}
|
|
62107
62248
|
|
|
62108
62249
|
// src/components/storyboard/StoryboardSourceEditor.tsx
|
|
62109
|
-
import { useCallback as useCallback138, useEffect as useEffect95, useMemo as
|
|
62250
|
+
import { useCallback as useCallback138, useEffect as useEffect95, useMemo as useMemo47, useRef as useRef118, useState as useState113 } from "react";
|
|
62110
62251
|
import { marked } from "marked";
|
|
62111
62252
|
import DOMPurify from "dompurify";
|
|
62112
62253
|
import { jsx as jsx152, jsxs as jsxs130 } from "react/jsx-runtime";
|
|
@@ -62165,7 +62306,7 @@ function useMarkdownPreview(source) {
|
|
|
62165
62306
|
const id = window.setTimeout(() => setDebounced(source), 200);
|
|
62166
62307
|
return () => window.clearTimeout(id);
|
|
62167
62308
|
}, [source]);
|
|
62168
|
-
return
|
|
62309
|
+
return useMemo47(() => {
|
|
62169
62310
|
const html2 = marked.parse(debounced, { async: false });
|
|
62170
62311
|
DOMPurify.addHook("afterSanitizeAttributes", hardenLinks);
|
|
62171
62312
|
try {
|
|
@@ -62484,7 +62625,7 @@ function StatusRow({
|
|
|
62484
62625
|
}
|
|
62485
62626
|
|
|
62486
62627
|
// src/components/storyboard/useFrameComments.ts
|
|
62487
|
-
import { useCallback as useCallback140, useEffect as useEffect97, useMemo as
|
|
62628
|
+
import { useCallback as useCallback140, useEffect as useEffect97, useMemo as useMemo48, useState as useState115 } from "react";
|
|
62488
62629
|
|
|
62489
62630
|
// src/components/storyboard/frameComments.ts
|
|
62490
62631
|
var FRAME_COMMENTS_PATH = ".hyperframes/frame-comments.json";
|
|
@@ -62565,7 +62706,7 @@ function useFrameComments(frames) {
|
|
|
62565
62706
|
const setDraft = useCallback140((index, text) => {
|
|
62566
62707
|
setDrafts((prev) => ({ ...prev, [index]: text }));
|
|
62567
62708
|
}, []);
|
|
62568
|
-
const draftCount =
|
|
62709
|
+
const draftCount = useMemo48(
|
|
62569
62710
|
() => Object.values(drafts).filter((text) => text.trim().length > 0).length,
|
|
62570
62711
|
[drafts]
|
|
62571
62712
|
);
|
|
@@ -62606,7 +62747,7 @@ function StoryboardLoaded({
|
|
|
62606
62747
|
useEffect98(() => {
|
|
62607
62748
|
void refreshPending();
|
|
62608
62749
|
}, [data.signature, refreshPending]);
|
|
62609
|
-
const sourceFiles =
|
|
62750
|
+
const sourceFiles = useMemo49(() => {
|
|
62610
62751
|
const files = [{ path: data.path, label: data.path }];
|
|
62611
62752
|
if (data.script?.exists) files.push({ path: data.script.path, label: data.script.path });
|
|
62612
62753
|
return files;
|
|
@@ -62958,7 +63099,7 @@ function StudioApp() {
|
|
|
62958
63099
|
const isPlaying = usePlayerStore((s) => s.isPlaying);
|
|
62959
63100
|
const isMasterView = !activeCompPath || activeCompPath === "index.html";
|
|
62960
63101
|
const activePreviewUrl = activeCompPath ? `/api/projects/${projectId}/preview/comp/${activeCompPath}` : null;
|
|
62961
|
-
const effectiveTimelineDuration =
|
|
63102
|
+
const effectiveTimelineDuration = useMemo50(() => {
|
|
62962
63103
|
const maxEnd = timelineElements.length > 0 ? Math.max(...timelineElements.map((el) => el.start + el.duration)) : 0;
|
|
62963
63104
|
return Math.max(timelineDuration, maxEnd);
|
|
62964
63105
|
}, [timelineDuration, timelineElements]);
|
|
@@ -62980,7 +63121,7 @@ function StudioApp() {
|
|
|
62980
63121
|
domEditSaveTimestampRef,
|
|
62981
63122
|
setRefreshKey
|
|
62982
63123
|
});
|
|
62983
|
-
const masterCompPath =
|
|
63124
|
+
const masterCompPath = useMemo50(
|
|
62984
63125
|
() => resolveMasterCompositionPath(fileManager.fileTree),
|
|
62985
63126
|
[fileManager.fileTree]
|
|
62986
63127
|
);
|
|
@@ -63018,6 +63159,7 @@ function StudioApp() {
|
|
|
63018
63159
|
timelineElements,
|
|
63019
63160
|
showToast,
|
|
63020
63161
|
writeProjectFile: fileManager.writeProjectFile,
|
|
63162
|
+
observeProjectFileVersion: fileManager.observeProjectFileVersion,
|
|
63021
63163
|
recordEdit: editHistory.recordEdit,
|
|
63022
63164
|
domEditSaveTimestampRef,
|
|
63023
63165
|
reloadPreview,
|
|
@@ -63296,7 +63438,7 @@ function StudioApp() {
|
|
|
63296
63438
|
handlePreviewIframeRef,
|
|
63297
63439
|
refreshPreviewDocumentVersion
|
|
63298
63440
|
});
|
|
63299
|
-
const timelineToolbar =
|
|
63441
|
+
const timelineToolbar = useMemo50(
|
|
63300
63442
|
() => /* @__PURE__ */ jsx157(
|
|
63301
63443
|
TimelineToolbar,
|
|
63302
63444
|
{
|