@hyperframes/studio 0.8.142 → 0.8.144
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/assets/hyperframes-player-Bw_jIaSX.js +473 -0
- package/dist/assets/{index-B-wffzRH.js → index-BVM9NuWl.js} +153 -153
- package/dist/assets/{index-D3Vij9t1.js → index-Cj7W_c7p.js} +1 -1
- package/dist/assets/{index-D5q2_7Gw.js → index-DyH9dT7b.js} +1 -1
- package/dist/{chunk-TFLU2MGI.js → chunk-3GHTHPZD.js} +8 -1
- package/dist/chunk-3GHTHPZD.js.map +1 -0
- package/dist/{chunk-H2DUOXTF.js → chunk-G3EDKRZH.js} +3 -3
- package/dist/{chunk-UYWON5AX.js → chunk-PEAKCOUW.js} +7 -3
- package/dist/chunk-PEAKCOUW.js.map +1 -0
- package/dist/{chunk-LOVBLSMR.js → chunk-Y2OHHNM2.js} +35 -19
- package/dist/chunk-Y2OHHNM2.js.map +1 -0
- package/dist/{domEditingLayers-KBTPQKGA.js → domEditingLayers-PYST4G45.js} +3 -3
- package/dist/index.html +1 -1
- package/dist/index.js +261 -230
- package/dist/index.js.map +1 -1
- package/dist/player.js +3 -3
- package/dist/ui.d.ts +4 -5
- package/dist/ui.js +1 -1
- package/package.json +8 -8
- package/src/components/MediaPreview.tsx +2 -1
- package/src/components/editor/DomEditSelectionChrome.test.tsx +103 -0
- package/src/components/editor/DomEditSelectionChrome.tsx +42 -16
- package/src/components/editor/anchoredResizeCommitFeedsOffset.test.ts +36 -0
- package/src/components/editor/domEditOverlayGestures.ts +1 -0
- package/src/components/editor/domEditOverlayStartGesture.ts +5 -0
- package/src/components/editor/domEditResizeLocal.test.ts +81 -1
- package/src/components/editor/domEditResizeLocal.ts +27 -3
- package/src/components/editor/domEditingLayers.ts +4 -1
- package/src/components/editor/domEditingTextFields.test.ts +18 -0
- package/src/components/editor/manualEditsDom.ts +12 -12
- package/src/components/editor/mediaAudioEdits.test.ts +12 -0
- package/src/components/editor/mediaAudioEdits.ts +5 -5
- package/src/components/editor/previewGestureStarts.ts +14 -5
- package/src/components/editor/propertyPanelFill.tsx +2 -1
- package/src/components/editor/propertyPanelFlatMediaSection.tsx +3 -4
- package/src/components/editor/propertyPanelMediaSection.tsx +3 -4
- package/src/components/editor/resizeDraft.ts +13 -4
- package/src/components/editor/useColorGradingController.ts +2 -1
- package/src/components/editor/useDomEditOverlayGestures.ts +5 -3
- package/src/components/ui/Menu.test.tsx +67 -5
- package/src/components/ui/Menu.tsx +21 -4
- package/src/components/ui/Popover.tsx +11 -5
- package/src/hooks/gsapResizeIntercept.test.ts +46 -11
- package/src/hooks/gsapResizeIntercept.ts +25 -20
- package/src/hooks/useDomEditCommits.ts +2 -1
- package/src/hooks/useFileManager.ts +2 -1
- package/src/hooks/useFileTree.ts +2 -1
- package/src/hooks/useRenderClipContent.ts +15 -3
- package/src/hooks/useThumbnailStripSize.test.tsx +123 -0
- package/src/hooks/useThumbnailStripSize.ts +19 -8
- package/src/player/components/CompositionThumbnail.test.ts +3 -0
- package/src/player/components/ImageThumbnail.test.tsx +4 -1
- package/src/player/components/VideoThumbnail.test.tsx +13 -2
- package/src/player/components/clipMenuNormalize.ts +2 -2
- package/src/player/components/clipPeakMap.ts +2 -2
- package/src/player/components/thumbnailUtils.test.ts +33 -0
- package/src/player/components/thumbnailUtils.ts +5 -0
- package/src/player/hooks/timelineSyncHydration.ts +2 -1
- package/src/player/lib/mediaProbe.test.ts +12 -0
- package/src/player/lib/mediaProbe.ts +4 -2
- package/src/utils/authoredSource.test.ts +25 -0
- package/src/utils/authoredSource.ts +3 -5
- package/src/utils/rounding.ts +7 -0
- package/src/utils/sourcePatcher.test.ts +135 -0
- package/src/utils/sourcePatcher.ts +102 -186
- package/src/utils/studioHelpers.test.ts +23 -0
- package/src/utils/studioHelpers.ts +3 -2
- package/src/utils/studioSelectionSnapshot.test.ts +31 -0
- package/src/utils/timelineAssetDrop.test.ts +14 -0
- package/src/utils/timelineAssetDrop.ts +2 -1
- package/dist/assets/hyperframes-player-sAsRuV73.js +0 -473
- package/dist/chunk-LOVBLSMR.js.map +0 -1
- package/dist/chunk-TFLU2MGI.js.map +0 -1
- package/dist/chunk-UYWON5AX.js.map +0 -1
- /package/dist/{chunk-H2DUOXTF.js.map → chunk-G3EDKRZH.js.map} +0 -0
- /package/dist/{domEditingLayers-KBTPQKGA.js.map → domEditingLayers-PYST4G45.js.map} +0 -0
package/dist/index.js
CHANGED
|
@@ -40,7 +40,7 @@ import {
|
|
|
40
40
|
usePreviewVariablesStore,
|
|
41
41
|
whenPreviewBooted,
|
|
42
42
|
writeStudioUiPreferences
|
|
43
|
-
} from "./chunk-
|
|
43
|
+
} from "./chunk-G3EDKRZH.js";
|
|
44
44
|
import {
|
|
45
45
|
Button,
|
|
46
46
|
ContextMenu,
|
|
@@ -72,7 +72,7 @@ import {
|
|
|
72
72
|
fieldBase,
|
|
73
73
|
fieldText,
|
|
74
74
|
popupSurface
|
|
75
|
-
} from "./chunk-
|
|
75
|
+
} from "./chunk-Y2OHHNM2.js";
|
|
76
76
|
import {
|
|
77
77
|
DOM_EDIT_LAYER_OBSERVER_INIT,
|
|
78
78
|
STUDIO_FLAT_INSPECTOR_ENABLED,
|
|
@@ -105,7 +105,7 @@ import {
|
|
|
105
105
|
resolveDomEditSelection,
|
|
106
106
|
serializeDomEditTextFields,
|
|
107
107
|
studioApiFetch
|
|
108
|
-
} from "./chunk-
|
|
108
|
+
} from "./chunk-PEAKCOUW.js";
|
|
109
109
|
import {
|
|
110
110
|
LAYER_REVEAL_PRIOR_POSITION_ATTR,
|
|
111
111
|
LAYER_REVEAL_PRIOR_Z_ATTR,
|
|
@@ -158,13 +158,14 @@ import {
|
|
|
158
158
|
roundTo3,
|
|
159
159
|
roundToCenti,
|
|
160
160
|
roundToLayoutPx,
|
|
161
|
+
roundToLayoutSize,
|
|
161
162
|
runtimeAudioId,
|
|
162
163
|
sameTimelineText,
|
|
163
164
|
setCompositionSourceMap,
|
|
164
165
|
splitTimelineElementKey,
|
|
165
166
|
toHexColor,
|
|
166
167
|
wrapTimeline
|
|
167
|
-
} from "./chunk-
|
|
168
|
+
} from "./chunk-3GHTHPZD.js";
|
|
168
169
|
import "./chunk-PZ5AY32C.js";
|
|
169
170
|
|
|
170
171
|
// src/components/EditorShell.tsx
|
|
@@ -3597,6 +3598,7 @@ function useTimelineZoom() {
|
|
|
3597
3598
|
import { useCallback as useCallback5, useEffect as useEffect6, useRef as useRef6, useState as useState4 } from "react";
|
|
3598
3599
|
|
|
3599
3600
|
// src/utils/timelineAssetDrop.ts
|
|
3601
|
+
import { encodeUrlPath } from "@hyperframes/parsers";
|
|
3600
3602
|
import { buildTimelineAssetId } from "@hyperframes/core/timeline-asset-id";
|
|
3601
3603
|
|
|
3602
3604
|
// src/utils/mediaTypes.ts
|
|
@@ -3701,7 +3703,7 @@ function fitTimelineAssetGeometry(natural, comp) {
|
|
|
3701
3703
|
};
|
|
3702
3704
|
}
|
|
3703
3705
|
function buildTimelineAssetInsertHtml(input) {
|
|
3704
|
-
const sharedAttrs = `id="${input.id}" data-hf-id="${input.hfId}" class="clip" src="${input.assetPath}" data-start="${input.start}" data-duration="${input.duration}" data-track-index="${input.track}"`;
|
|
3706
|
+
const sharedAttrs = `id="${input.id}" data-hf-id="${input.hfId}" class="clip" src="${encodeUrlPath(input.assetPath)}" data-start="${input.start}" data-duration="${input.duration}" data-track-index="${input.track}"`;
|
|
3705
3707
|
const geometry = input.geometry ?? { left: 0, top: 0, width: 640, height: 360 };
|
|
3706
3708
|
const visualStyles = `position: absolute; left: ${geometry.left}px; top: ${geometry.top}px; width: ${geometry.width}px; height: ${geometry.height}px; object-fit: contain; z-index: ${input.zIndex}`;
|
|
3707
3709
|
if (input.kind === "image") {
|
|
@@ -16485,17 +16487,24 @@ var measure = (entries) => isTimelineZoomPreviewing() || commit(
|
|
|
16485
16487
|
})
|
|
16486
16488
|
);
|
|
16487
16489
|
var onPresence = (entries) => measure(entries.filter((entry2) => entry2.isIntersecting));
|
|
16488
|
-
var
|
|
16489
|
-
|
|
16490
|
-
|
|
16491
|
-
|
|
16492
|
-
}))
|
|
16493
|
-
);
|
|
16490
|
+
var pendingSizes = /* @__PURE__ */ new Map();
|
|
16491
|
+
var pendingSizesFrame = 0;
|
|
16492
|
+
var applyPendingSizes = () => {
|
|
16493
|
+
pendingSizesFrame = 0;
|
|
16494
|
+
const entries = [...pendingSizes].map(([target, size]) => ({ target, size }));
|
|
16495
|
+
pendingSizes.clear();
|
|
16496
|
+
measure(entries);
|
|
16497
|
+
};
|
|
16498
|
+
var applyResizesNextFrame = (entries) => {
|
|
16499
|
+
for (const { target, contentRect } of entries)
|
|
16500
|
+
pendingSizes.set(target, { width: contentRect.width, height: contentRect.height });
|
|
16501
|
+
pendingSizesFrame ||= requestAnimationFrame(applyPendingSizes);
|
|
16502
|
+
};
|
|
16494
16503
|
var observeIntersections = (callback) => typeof IntersectionObserver === "undefined" ? null : new IntersectionObserver(callback, GAP_WARNING);
|
|
16495
16504
|
function acquire() {
|
|
16496
16505
|
if (users++ === 0) {
|
|
16497
16506
|
shared = {
|
|
16498
|
-
resize: new ResizeObserver(
|
|
16507
|
+
resize: new ResizeObserver(applyResizesNextFrame),
|
|
16499
16508
|
presence: observeIntersections(onPresence),
|
|
16500
16509
|
gaps: observeIntersections(
|
|
16501
16510
|
(entries) => entries.some((entry2) => entry2.isIntersecting) && scheduleRefresh()
|
|
@@ -16516,6 +16525,9 @@ function release() {
|
|
|
16516
16525
|
window.removeEventListener("scroll", scheduleRefresh, { capture: true });
|
|
16517
16526
|
cancelAnimationFrame(frame2);
|
|
16518
16527
|
frame2 = 0;
|
|
16528
|
+
cancelAnimationFrame(pendingSizesFrame);
|
|
16529
|
+
pendingSizesFrame = 0;
|
|
16530
|
+
pendingSizes.clear();
|
|
16519
16531
|
}
|
|
16520
16532
|
var watchGap = (gap) => {
|
|
16521
16533
|
if (!gap) return;
|
|
@@ -16556,6 +16568,7 @@ function useThumbnailStripSize() {
|
|
|
16556
16568
|
resize.unobserve(target);
|
|
16557
16569
|
presence?.unobserve(target);
|
|
16558
16570
|
strips.delete(target);
|
|
16571
|
+
pendingSizes.delete(target);
|
|
16559
16572
|
release();
|
|
16560
16573
|
};
|
|
16561
16574
|
}, []);
|
|
@@ -17143,17 +17156,41 @@ function useOwnPreviewIframe() {
|
|
|
17143
17156
|
import { isHtmlElement as isHtmlElement4 } from "@hyperframes/core/runtime/dom-realm";
|
|
17144
17157
|
|
|
17145
17158
|
// src/utils/sourcePatcher.ts
|
|
17159
|
+
import {
|
|
17160
|
+
scanHtmlOpeningTags,
|
|
17161
|
+
decodeAuthoredAttribute,
|
|
17162
|
+
HTML_ATTRIBUTE_ENTITIES
|
|
17163
|
+
} from "@hyperframes/parsers";
|
|
17146
17164
|
function escapeRegex(s) {
|
|
17147
17165
|
return s.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
17148
17166
|
}
|
|
17167
|
+
function tagAttribute(tag, name) {
|
|
17168
|
+
return scanHtmlOpeningTags(tag)[0]?.attributes.find((attr) => attr.name === name.toLowerCase());
|
|
17169
|
+
}
|
|
17170
|
+
function patchTagAttribute(tag, name, edit) {
|
|
17171
|
+
if (edit.kind === "remove") {
|
|
17172
|
+
const attributes = scanHtmlOpeningTags(tag)[0]?.attributes.filter((attr2) => attr2.name === name.toLowerCase()) ?? [];
|
|
17173
|
+
const parts = [];
|
|
17174
|
+
let cursor = 0;
|
|
17175
|
+
for (const attribute of attributes) {
|
|
17176
|
+
let start = attribute.start;
|
|
17177
|
+
while (start > cursor && /[\t\n\f\r ]/.test(tag[start - 1])) start--;
|
|
17178
|
+
parts.push(tag.slice(cursor, start));
|
|
17179
|
+
cursor = attribute.end;
|
|
17180
|
+
}
|
|
17181
|
+
parts.push(tag.slice(cursor));
|
|
17182
|
+
return parts.join("");
|
|
17183
|
+
}
|
|
17184
|
+
const attr = tagAttribute(tag, name);
|
|
17185
|
+
const replacement = edit.kind === "boolean" ? name : `${name}="${escapeHtmlAttribute(edit.value)}"`;
|
|
17186
|
+
if (attr) return tag.slice(0, attr.start) + replacement + tag.slice(attr.end);
|
|
17187
|
+
return tag.endsWith("/") ? `${tag.slice(0, -1).trimEnd()} ${replacement} /` : `${tag} ${replacement}`;
|
|
17188
|
+
}
|
|
17149
17189
|
function escapeStyleAttributeValue(value, quote) {
|
|
17150
17190
|
return quote === '"' ? value.replace(/"/g, """) : value.replace(/'/g, "'");
|
|
17151
17191
|
}
|
|
17152
17192
|
function escapeHtmlAttribute(value) {
|
|
17153
|
-
return value.replace(
|
|
17154
|
-
}
|
|
17155
|
-
function unescapeHtmlAttribute(value) {
|
|
17156
|
-
return value.replace(/"/g, '"').replace(/</g, "<").replace(/>/g, ">").replace(/&/g, "&");
|
|
17193
|
+
return value.replace(/[&"<>]/g, (char) => HTML_ATTRIBUTE_ENTITIES[char][0]);
|
|
17157
17194
|
}
|
|
17158
17195
|
function splitInlineStyleDeclarations(style) {
|
|
17159
17196
|
const declarations = [];
|
|
@@ -17206,7 +17243,7 @@ function resolveSourceFile(elementId2, selector, files) {
|
|
|
17206
17243
|
if (!elementId2 && !selector) return null;
|
|
17207
17244
|
if (elementId2) {
|
|
17208
17245
|
for (const [path, content] of Object.entries(files)) {
|
|
17209
|
-
if (content
|
|
17246
|
+
if (findTagByAttribute(content, "id", elementId2)) {
|
|
17210
17247
|
return path;
|
|
17211
17248
|
}
|
|
17212
17249
|
}
|
|
@@ -17215,7 +17252,7 @@ function resolveSourceFile(elementId2, selector, files) {
|
|
|
17215
17252
|
if (compIdMatch) {
|
|
17216
17253
|
const compId = compIdMatch[1];
|
|
17217
17254
|
for (const [path, content] of Object.entries(files)) {
|
|
17218
|
-
if (content
|
|
17255
|
+
if (findTagByAttribute(content, "data-composition-id", compId)) {
|
|
17219
17256
|
return path;
|
|
17220
17257
|
}
|
|
17221
17258
|
}
|
|
@@ -17224,7 +17261,7 @@ function resolveSourceFile(elementId2, selector, files) {
|
|
|
17224
17261
|
if (classMatch) {
|
|
17225
17262
|
const cls = classMatch[1];
|
|
17226
17263
|
for (const [path, content] of Object.entries(files)) {
|
|
17227
|
-
if (content
|
|
17264
|
+
if (findTagByClass(content, { selector: `.${cls}` })) {
|
|
17228
17265
|
return path;
|
|
17229
17266
|
}
|
|
17230
17267
|
}
|
|
@@ -17233,18 +17270,14 @@ function resolveSourceFile(elementId2, selector, files) {
|
|
|
17233
17270
|
return null;
|
|
17234
17271
|
}
|
|
17235
17272
|
function patchInlineStyle(html2, elementId2, prop, value) {
|
|
17236
|
-
|
|
17237
|
-
|
|
17238
|
-
|
|
17239
|
-
|
|
17240
|
-
|
|
17241
|
-
|
|
17242
|
-
|
|
17243
|
-
|
|
17244
|
-
const styleMatch = /\bstyle=(")([^"]*)"|\bstyle=(')([^']*)'/.exec(tag);
|
|
17245
|
-
if (styleMatch) {
|
|
17246
|
-
const existingStyle = styleMatch[2] ?? styleMatch[4];
|
|
17247
|
-
const quote = styleMatch[1] ?? styleMatch[3];
|
|
17273
|
+
return patchInlineStyleByTarget(html2, { id: elementId2 }, prop, value);
|
|
17274
|
+
}
|
|
17275
|
+
function patchInlineStyleInTag(tag, prop, value) {
|
|
17276
|
+
if (!tag) return tag;
|
|
17277
|
+
const styleMatch = tagAttribute(tag, "style");
|
|
17278
|
+
if (styleMatch?.kind === "value") {
|
|
17279
|
+
const existingStyle = styleMatch.value;
|
|
17280
|
+
const quote = styleMatch.quote || '"';
|
|
17248
17281
|
const props = /* @__PURE__ */ new Map();
|
|
17249
17282
|
for (const part of splitInlineStyleDeclarations(existingStyle)) {
|
|
17250
17283
|
const colon = part.indexOf(":");
|
|
@@ -17259,67 +17292,54 @@ function patchInlineStyleInTag(html2, tag, prop, value) {
|
|
|
17259
17292
|
props.set(prop, value);
|
|
17260
17293
|
}
|
|
17261
17294
|
const newStyle = Array.from(props.entries()).map(([k, v]) => `${k}: ${escapeStyleAttributeValue(v, quote)}`).join("; ");
|
|
17262
|
-
const newTag = tag.
|
|
17263
|
-
return
|
|
17295
|
+
const newTag = tag.slice(0, styleMatch.start) + `style=${quote}${newStyle}${quote}` + tag.slice(styleMatch.end);
|
|
17296
|
+
return newTag;
|
|
17264
17297
|
} else {
|
|
17265
|
-
if (value === null) return
|
|
17298
|
+
if (value === null) return tag;
|
|
17266
17299
|
const selfClosing = tag.endsWith("/");
|
|
17267
17300
|
const base2 = selfClosing ? tag.slice(0, -1).trimEnd() : tag;
|
|
17268
17301
|
const newTag = `${base2} style="${prop}: ${escapeStyleAttributeValue(value, '"')}"${selfClosing ? " /" : ""}`;
|
|
17269
|
-
return
|
|
17302
|
+
return newTag;
|
|
17270
17303
|
}
|
|
17271
17304
|
}
|
|
17272
17305
|
function patchInlineStyleByTarget(html2, target, prop, value) {
|
|
17273
17306
|
const match = findTagByTarget(html2, target);
|
|
17274
17307
|
if (!match) return html2;
|
|
17275
|
-
const newTag = patchInlineStyleInTag(match.tag,
|
|
17308
|
+
const newTag = patchInlineStyleInTag(match.tag, prop, value);
|
|
17276
17309
|
return replaceTagAtMatch(html2, match, newTag);
|
|
17277
17310
|
}
|
|
17278
17311
|
function replaceTagAtMatch(html2, match, newTag) {
|
|
17279
17312
|
return `${html2.slice(0, match.start)}${newTag}${html2.slice(match.end)}`;
|
|
17280
17313
|
}
|
|
17281
|
-
function
|
|
17282
|
-
const
|
|
17283
|
-
|
|
17284
|
-
|
|
17285
|
-
|
|
17314
|
+
function findTagByAttribute(html2, name, value) {
|
|
17315
|
+
const found = scanHtmlOpeningTags(html2).find((tag) => {
|
|
17316
|
+
const attr = tag.attributes.find((attr2) => attr2.name === name);
|
|
17317
|
+
return tag.closed && attr?.kind === "value" && decodeAuthoredAttribute(attr.value) === value;
|
|
17318
|
+
});
|
|
17319
|
+
return found ? { tag: html2.slice(found.start, found.bodyEnd), start: found.start, end: found.bodyEnd } : null;
|
|
17286
17320
|
}
|
|
17287
17321
|
function findTagByClass(html2, target) {
|
|
17288
17322
|
const classMatch = target.selector?.match(/^\.([a-zA-Z0-9_-]+)$/);
|
|
17289
17323
|
if (!classMatch) return null;
|
|
17290
|
-
const
|
|
17291
|
-
|
|
17292
|
-
|
|
17293
|
-
|
|
17294
|
-
);
|
|
17295
|
-
const selectorIndex = target.selectorIndex ?? 0;
|
|
17296
|
-
let match;
|
|
17297
|
-
let currentIndex = 0;
|
|
17298
|
-
while ((match = pattern.exec(html2)) !== null) {
|
|
17299
|
-
if (currentIndex === selectorIndex && match.index != null) {
|
|
17300
|
-
return {
|
|
17301
|
-
tag: match[1],
|
|
17302
|
-
start: match.index,
|
|
17303
|
-
end: match.index + match[1].length
|
|
17304
|
-
};
|
|
17305
|
-
}
|
|
17306
|
-
currentIndex += 1;
|
|
17307
|
-
}
|
|
17308
|
-
return null;
|
|
17324
|
+
const found = scanHtmlOpeningTags(html2).filter((tag) => {
|
|
17325
|
+
const attr = tag.attributes.find((attr2) => attr2.name === "class");
|
|
17326
|
+
return tag.closed && attr?.kind === "value" && decodeAuthoredAttribute(attr.value).split(/\s+/).includes(classMatch[1]);
|
|
17327
|
+
})[target.selectorIndex ?? 0];
|
|
17328
|
+
return found ? { tag: html2.slice(found.start, found.bodyEnd), start: found.start, end: found.bodyEnd } : null;
|
|
17309
17329
|
}
|
|
17310
17330
|
function findTagByTarget(html2, target) {
|
|
17311
17331
|
if (target.hfId) {
|
|
17312
|
-
const result =
|
|
17332
|
+
const result = findTagByAttribute(html2, "data-hf-id", target.hfId);
|
|
17313
17333
|
if (result) return result;
|
|
17314
17334
|
}
|
|
17315
17335
|
if (target.id) {
|
|
17316
|
-
const result =
|
|
17336
|
+
const result = findTagByAttribute(html2, "id", target.id);
|
|
17317
17337
|
if (result) return result;
|
|
17318
17338
|
}
|
|
17319
17339
|
if (!target.selector) return null;
|
|
17320
17340
|
const compositionIdMatch = target.selector.match(/^\[data-composition-id="([^"]+)"\]$/);
|
|
17321
17341
|
if (compositionIdMatch) {
|
|
17322
|
-
const result =
|
|
17342
|
+
const result = findTagByAttribute(html2, "data-composition-id", compositionIdMatch[1]);
|
|
17323
17343
|
if (result) return result;
|
|
17324
17344
|
}
|
|
17325
17345
|
return findTagByClass(html2, target);
|
|
@@ -17327,9 +17347,11 @@ function findTagByTarget(html2, target) {
|
|
|
17327
17347
|
function readAttributeByTarget(html2, target, attr) {
|
|
17328
17348
|
const match = findTagByTarget(html2, target);
|
|
17329
17349
|
if (!match) return void 0;
|
|
17330
|
-
|
|
17331
|
-
|
|
17332
|
-
|
|
17350
|
+
return readTagAttribute(match.tag, attr.startsWith("data-") ? attr : `data-${attr}`);
|
|
17351
|
+
}
|
|
17352
|
+
function readTagAttribute(tag, attr) {
|
|
17353
|
+
const value = tagAttribute(tag, attr);
|
|
17354
|
+
return value?.kind === "value" ? decodeAuthoredAttribute(value.value) : void 0;
|
|
17333
17355
|
}
|
|
17334
17356
|
function readTagSnippetByTarget(html2, target) {
|
|
17335
17357
|
const match = findTagByTarget(html2, target);
|
|
@@ -17338,60 +17360,15 @@ function readTagSnippetByTarget(html2, target) {
|
|
|
17338
17360
|
function patchAttributeByTarget(html2, target, attr, value) {
|
|
17339
17361
|
const match = findTagByTarget(html2, target);
|
|
17340
17362
|
if (!match) return html2;
|
|
17341
|
-
const
|
|
17342
|
-
const
|
|
17343
|
-
|
|
17344
|
-
if (value === null) {
|
|
17345
|
-
const boolAttrPattern = new RegExp(`\\b${escapeRegex(fullAttr)}(?:=(["'])[^"']*\\1)?`);
|
|
17346
|
-
if (!boolAttrPattern.test(tag)) return html2;
|
|
17347
|
-
const removePattern = new RegExp(`\\s+${escapeRegex(fullAttr)}(?:=(["'])[^"']*\\1)?`);
|
|
17348
|
-
const newTag2 = tag.replace(removePattern, "");
|
|
17349
|
-
return replaceTagAtMatch(html2, match, newTag2);
|
|
17350
|
-
}
|
|
17351
|
-
const escaped = escapeHtmlAttribute(value);
|
|
17352
|
-
if (attrPattern.test(tag)) {
|
|
17353
|
-
const newTag2 = tag.replace(attrPattern, `${fullAttr}="${escaped}"`);
|
|
17354
|
-
return replaceTagAtMatch(html2, match, newTag2);
|
|
17355
|
-
}
|
|
17356
|
-
const newTag = tag + ` ${fullAttr}="${escaped}"`;
|
|
17357
|
-
return replaceTagAtMatch(html2, match, newTag);
|
|
17363
|
+
const name = attr.startsWith("data-") ? attr : `data-${attr}`;
|
|
17364
|
+
const edit = value === null ? { kind: "remove" } : { kind: "value", value };
|
|
17365
|
+
return replaceTagAtMatch(html2, match, patchTagAttribute(match.tag, name, edit));
|
|
17358
17366
|
}
|
|
17359
17367
|
function patchAttribute(html2, elementId2, attr, value) {
|
|
17360
|
-
|
|
17361
|
-
const match = idPattern.exec(html2);
|
|
17362
|
-
if (!match) return html2;
|
|
17363
|
-
const tag = match[1];
|
|
17364
|
-
const fullAttr = attr.startsWith("data-") ? attr : `data-${attr}`;
|
|
17365
|
-
const attrPattern = new RegExp(`\\b${escapeRegex(fullAttr)}=(["'])([^"']*)\\1`);
|
|
17366
|
-
if (value === null) {
|
|
17367
|
-
const boolAttrPattern = new RegExp(`\\b${escapeRegex(fullAttr)}(?:=(["'])[^"']*\\1)?`);
|
|
17368
|
-
if (!boolAttrPattern.test(tag)) return html2;
|
|
17369
|
-
const removePattern = new RegExp(`\\s+${escapeRegex(fullAttr)}(?:=(["'])[^"']*\\1)?`);
|
|
17370
|
-
const newTag = tag.replace(removePattern, "");
|
|
17371
|
-
return html2.replace(tag, newTag);
|
|
17372
|
-
}
|
|
17373
|
-
const escaped = escapeHtmlAttribute(value);
|
|
17374
|
-
if (attrPattern.test(tag)) {
|
|
17375
|
-
const newTag = tag.replace(attrPattern, `${fullAttr}="${escaped}"`);
|
|
17376
|
-
return html2.replace(tag, newTag);
|
|
17377
|
-
} else {
|
|
17378
|
-
const newTag = tag + ` ${fullAttr}="${escaped}"`;
|
|
17379
|
-
return html2.replace(tag, newTag);
|
|
17380
|
-
}
|
|
17368
|
+
return patchAttributeByTarget(html2, { id: elementId2 }, attr, value);
|
|
17381
17369
|
}
|
|
17382
17370
|
function patchTextContent(html2, elementId2, value) {
|
|
17383
|
-
|
|
17384
|
-
`(<([a-z0-9-]+)[^>]*\\bid=(["'])${escapeRegex(elementId2)}\\3[^>]*>)`,
|
|
17385
|
-
"i"
|
|
17386
|
-
);
|
|
17387
|
-
const match = openTagPattern.exec(html2);
|
|
17388
|
-
if (!match || match.index == null) return html2;
|
|
17389
|
-
const openingTag = match[1];
|
|
17390
|
-
const tagName = match[2];
|
|
17391
|
-
const contentStart = match.index + openingTag.length;
|
|
17392
|
-
const closingIndex = findMatchingClosingTagIndex(html2, tagName, contentStart);
|
|
17393
|
-
if (closingIndex < 0) return html2;
|
|
17394
|
-
return `${html2.slice(0, contentStart)}${value}${html2.slice(closingIndex)}`;
|
|
17371
|
+
return patchTextContentByTarget(html2, { id: elementId2 }, value);
|
|
17395
17372
|
}
|
|
17396
17373
|
function findMatchingClosingTagIndex(html2, tagName, contentStart) {
|
|
17397
17374
|
const tagPattern = new RegExp(`</?${escapeRegex(tagName)}\\b[^>]*>`, "gi");
|
|
@@ -17426,47 +17403,26 @@ var HTML_BOOLEAN_ATTRIBUTES = /* @__PURE__ */ new Set([
|
|
|
17426
17403
|
"reversed",
|
|
17427
17404
|
"selected"
|
|
17428
17405
|
]);
|
|
17429
|
-
function patchHtmlAttributeInTag(
|
|
17430
|
-
if (!tag) return
|
|
17431
|
-
|
|
17432
|
-
if (
|
|
17433
|
-
|
|
17434
|
-
|
|
17435
|
-
|
|
17436
|
-
|
|
17437
|
-
|
|
17438
|
-
|
|
17439
|
-
|
|
17440
|
-
|
|
17441
|
-
if (hasBoolAttr) return html2;
|
|
17442
|
-
const newTag2 = tag + ` ${attr}`;
|
|
17443
|
-
return html2.replace(tag, newTag2);
|
|
17444
|
-
}
|
|
17445
|
-
const attrPattern = new RegExp(`\\b${escapeRegex(attr)}=(["'])([^"']*)\\1`);
|
|
17446
|
-
if (value === null) {
|
|
17447
|
-
if (!attrPattern.test(tag)) return html2;
|
|
17448
|
-
const removePattern = new RegExp(`\\s+${escapeRegex(attr)}=(["'])[^"']*\\1`);
|
|
17449
|
-
const newTag2 = tag.replace(removePattern, "");
|
|
17450
|
-
return html2.replace(tag, newTag2);
|
|
17451
|
-
}
|
|
17452
|
-
const escaped = escapeHtmlAttribute(value);
|
|
17453
|
-
if (attrPattern.test(tag)) {
|
|
17454
|
-
const newTag2 = tag.replace(attrPattern, `${attr}="${escaped}"`);
|
|
17455
|
-
return html2.replace(tag, newTag2);
|
|
17456
|
-
}
|
|
17457
|
-
const newTag = tag + ` ${attr}="${escaped}"`;
|
|
17458
|
-
return html2.replace(tag, newTag);
|
|
17406
|
+
function patchHtmlAttributeInTag(tag, attr, value) {
|
|
17407
|
+
if (!tag) return tag;
|
|
17408
|
+
let edit;
|
|
17409
|
+
if (HTML_BOOLEAN_ATTRIBUTES.has(attr)) {
|
|
17410
|
+
if (value === null || value === "" || value === "false") edit = { kind: "remove" };
|
|
17411
|
+
else {
|
|
17412
|
+
if (tagAttribute(tag, attr)) return tag;
|
|
17413
|
+
edit = { kind: "boolean" };
|
|
17414
|
+
}
|
|
17415
|
+
} else edit = value === null ? { kind: "remove" } : { kind: "value", value };
|
|
17416
|
+
const newTag = patchTagAttribute(tag, attr, edit);
|
|
17417
|
+
return newTag;
|
|
17459
17418
|
}
|
|
17460
17419
|
function patchHtmlAttribute(html2, elementId2, attr, value) {
|
|
17461
|
-
|
|
17462
|
-
const match = idPattern.exec(html2);
|
|
17463
|
-
if (!match) return html2;
|
|
17464
|
-
return patchHtmlAttributeInTag(html2, match[1], attr, value);
|
|
17420
|
+
return patchHtmlAttributeByTarget(html2, { id: elementId2 }, attr, value);
|
|
17465
17421
|
}
|
|
17466
17422
|
function patchHtmlAttributeByTarget(html2, target, attr, value) {
|
|
17467
17423
|
const match = findTagByTarget(html2, target);
|
|
17468
17424
|
if (!match) return html2;
|
|
17469
|
-
const newTag = patchHtmlAttributeInTag(match.tag,
|
|
17425
|
+
const newTag = patchHtmlAttributeInTag(match.tag, attr, value);
|
|
17470
17426
|
return replaceTagAtMatch(html2, match, newTag);
|
|
17471
17427
|
}
|
|
17472
17428
|
function patchTextContentByTarget(html2, target, value) {
|
|
@@ -17631,8 +17587,8 @@ import { motionPathPluginUrl } from "@hyperframes/core/gsap-cdn";
|
|
|
17631
17587
|
// src/utils/authoredSource.ts
|
|
17632
17588
|
import { ensureHfIds, isCompositionTemplate } from "@hyperframes/parsers/hf-ids";
|
|
17633
17589
|
import {
|
|
17634
|
-
|
|
17635
|
-
|
|
17590
|
+
PREVIEW_ONLY_ATTRS,
|
|
17591
|
+
STUDIO_PREVIEW_LAZY_ATTR
|
|
17636
17592
|
} from "@hyperframes/core/studio-preview-mark";
|
|
17637
17593
|
function parseSavedSource(html2) {
|
|
17638
17594
|
return new DOMParser().parseFromString(ensureHfIds(html2), "text/html");
|
|
@@ -17713,10 +17669,8 @@ function authoredMarkup(authored, live, sourceFile) {
|
|
|
17713
17669
|
function liveMarkupWithoutPreviewMarks(live) {
|
|
17714
17670
|
const copy = live.cloneNode(true);
|
|
17715
17671
|
for (const el of [copy, ...Array.from(copy.querySelectorAll("*"))]) {
|
|
17716
|
-
el.removeAttribute(
|
|
17717
|
-
|
|
17718
|
-
el.removeAttribute("loading");
|
|
17719
|
-
el.removeAttribute(STUDIO_PREVIEW_LAZY_ATTR);
|
|
17672
|
+
if (el.hasAttribute(STUDIO_PREVIEW_LAZY_ATTR)) el.removeAttribute("loading");
|
|
17673
|
+
for (const attr of PREVIEW_ONLY_ATTRS) el.removeAttribute(attr);
|
|
17720
17674
|
}
|
|
17721
17675
|
return copy.outerHTML;
|
|
17722
17676
|
}
|
|
@@ -21837,6 +21791,7 @@ import {
|
|
|
21837
21791
|
} from "@hyperframes/core/audio-automation";
|
|
21838
21792
|
|
|
21839
21793
|
// src/utils/studioHelpers.ts
|
|
21794
|
+
import { encodeUrlPath as encodeUrlPath2 } from "@hyperframes/parsers";
|
|
21840
21795
|
function getTimelineElementLabel(element) {
|
|
21841
21796
|
return element.label || element.id || element.tag;
|
|
21842
21797
|
}
|
|
@@ -21991,7 +21946,7 @@ async function resolveDroppedAssetDuration(projectId, assetPath, kind) {
|
|
|
21991
21946
|
if (kind === "image") return DEFAULT_TIMELINE_ASSET_DURATION.image;
|
|
21992
21947
|
const media = document.createElement(kind === "video" ? "video" : "audio");
|
|
21993
21948
|
media.preload = "metadata";
|
|
21994
|
-
media.src = buildProjectApiPath(projectId, `/preview/${assetPath}`);
|
|
21949
|
+
media.src = buildProjectApiPath(projectId, `/preview/${encodeUrlPath2(assetPath)}`);
|
|
21995
21950
|
const duration = await new Promise((resolve) => {
|
|
21996
21951
|
const timeout = window.setTimeout(() => resolve(DEFAULT_TIMELINE_ASSET_DURATION[kind]), 3e3);
|
|
21997
21952
|
const finalize = (value) => {
|
|
@@ -25307,6 +25262,7 @@ function isPeakMap(value) {
|
|
|
25307
25262
|
}
|
|
25308
25263
|
|
|
25309
25264
|
// src/player/components/thumbnailUtils.ts
|
|
25265
|
+
import { decodedUrlPath } from "@hyperframes/parsers";
|
|
25310
25266
|
function quantizeThumbnailFrameCount(frameCount) {
|
|
25311
25267
|
const safeCount = Math.max(1, Number.isFinite(frameCount) ? Math.ceil(frameCount) : 1);
|
|
25312
25268
|
const cap = 2 ** Math.floor(Math.log2(MAX_VISIBLE_THUMBNAIL_FRAMES));
|
|
@@ -25357,6 +25313,9 @@ function computeThumbnailStrip(containerWidth, aspect, clipHeight, minFrameWidth
|
|
|
25357
25313
|
const frameCount = measured ? Math.max(1, Math.ceil(containerWidth / frameW)) : 1;
|
|
25358
25314
|
return { frameW, frameCount };
|
|
25359
25315
|
}
|
|
25316
|
+
function authoredSrcPath(src) {
|
|
25317
|
+
return /^(?:[a-z][a-z\d+.-]*:|\/\/)/i.test(src) ? src : decodedUrlPath(src);
|
|
25318
|
+
}
|
|
25360
25319
|
function encodePreviewPath(relativePath) {
|
|
25361
25320
|
return relativePath.split("/").map(encodeURIComponent).join("/");
|
|
25362
25321
|
}
|
|
@@ -25401,7 +25360,7 @@ function loadPeakMap(url) {
|
|
|
25401
25360
|
function clipPeaksUrl(src, projectId) {
|
|
25402
25361
|
const origin2 = window.location.origin;
|
|
25403
25362
|
const relative = resolvePreviewRelative(
|
|
25404
|
-
resolveMediaPreviewUrl(src ?? "", projectId, origin2),
|
|
25363
|
+
resolveMediaPreviewUrl(authoredSrcPath(src ?? ""), projectId, origin2),
|
|
25405
25364
|
projectId,
|
|
25406
25365
|
origin2
|
|
25407
25366
|
);
|
|
@@ -25472,7 +25431,7 @@ function isNormalizePlan(value) {
|
|
|
25472
25431
|
async function requestNormalizePlan(projectId, el, fetchImpl = studioApiFetch) {
|
|
25473
25432
|
const origin2 = window.location.origin;
|
|
25474
25433
|
const relative = resolvePreviewRelative(
|
|
25475
|
-
resolveMediaPreviewUrl(el.src ?? "", projectId, origin2),
|
|
25434
|
+
resolveMediaPreviewUrl(authoredSrcPath(el.src ?? ""), projectId, origin2),
|
|
25476
25435
|
projectId,
|
|
25477
25436
|
origin2
|
|
25478
25437
|
);
|
|
@@ -26986,10 +26945,10 @@ function formatAttrs(attrs) {
|
|
|
26986
26945
|
function readAuthoredSrc(source, target) {
|
|
26987
26946
|
const tag = findTagByTarget(source, target);
|
|
26988
26947
|
if (!tag) return "";
|
|
26989
|
-
const own =
|
|
26990
|
-
if (own
|
|
26991
|
-
const firstSource = /^\s*<source\b[^>]
|
|
26992
|
-
return firstSource
|
|
26948
|
+
const own = readTagAttribute(tag.tag, "src");
|
|
26949
|
+
if (own) return own;
|
|
26950
|
+
const firstSource = /^\s*<source\b[^>]*>/i.exec(source.slice(tag.end + 1));
|
|
26951
|
+
return firstSource && readTagAttribute(firstSource[0], "src") || "";
|
|
26993
26952
|
}
|
|
26994
26953
|
function insertBeforeTarget(source, target, markup) {
|
|
26995
26954
|
const match = findTagByTarget(source, target);
|
|
@@ -29960,9 +29919,10 @@ function buildStandaloneRootTimelineElement(params) {
|
|
|
29960
29919
|
|
|
29961
29920
|
// src/player/hooks/timelineSyncHydration.ts
|
|
29962
29921
|
import { resolveCssStackingContextId as resolveCssStackingContextId2 } from "@hyperframes/core/runtime/stacking-context";
|
|
29922
|
+
import { LOOP_INFLATED_TIMELINE_SECONDS } from "@hyperframes/core/runtime/composition-length";
|
|
29963
29923
|
import { HF_AUDIO_GROUP_ATTR as HF_AUDIO_GROUP_ATTR3 } from "@hyperframes/core/audio-groups";
|
|
29964
29924
|
function sanitizeDurationSeconds(value) {
|
|
29965
|
-
return Number.isFinite(value) && value > 0 && value <
|
|
29925
|
+
return Number.isFinite(value) && value > 0 && value < LOOP_INFLATED_TIMELINE_SECONDS ? value : 0;
|
|
29966
29926
|
}
|
|
29967
29927
|
function readChildAudioGroupState(child) {
|
|
29968
29928
|
const audioGroup = child.getAttribute(HF_AUDIO_GROUP_ATTR3);
|
|
@@ -31340,7 +31300,7 @@ function readParentFlexBasisPixels(element, size) {
|
|
|
31340
31300
|
const display2 = readStyleOrComputed(parent, "display").trim();
|
|
31341
31301
|
if (display2 !== "flex" && display2 !== "inline-flex") return null;
|
|
31342
31302
|
const direction = readStyleOrComputed(parent, "flex-direction").trim();
|
|
31343
|
-
return
|
|
31303
|
+
return direction.startsWith("column") ? size.height : size.width;
|
|
31344
31304
|
}
|
|
31345
31305
|
function restoreStaleStudioScaleResize(element) {
|
|
31346
31306
|
if (!element.hasAttribute(STUDIO_ORIGINAL_SCALE_ATTR)) return;
|
|
@@ -31403,17 +31363,16 @@ function writeStudioBoxSizeVars(element, size) {
|
|
|
31403
31363
|
element.setAttribute(STUDIO_ORIGINAL_DISPLAY_ATTR, element.style.getPropertyValue("display"));
|
|
31404
31364
|
}
|
|
31405
31365
|
element.setAttribute(STUDIO_BOX_SIZE_ATTR, "true");
|
|
31406
|
-
element.style.setProperty(STUDIO_WIDTH_PROP, `${
|
|
31407
|
-
element.style.setProperty(STUDIO_HEIGHT_PROP, `${
|
|
31366
|
+
element.style.setProperty(STUDIO_WIDTH_PROP, `${size.width}px`);
|
|
31367
|
+
element.style.setProperty(STUDIO_HEIGHT_PROP, `${size.height}px`);
|
|
31408
31368
|
}
|
|
31409
|
-
function applyStudioBoxSizeDimensions(element,
|
|
31369
|
+
function applyStudioBoxSizeDimensions(element, wantedSize) {
|
|
31370
|
+
const size = roundToLayoutSize(wantedSize);
|
|
31410
31371
|
writeStudioBoxSizeVars(element, size);
|
|
31411
31372
|
restoreStaleStudioScaleResize(element);
|
|
31412
|
-
const width = roundToLayoutPx(Math.max(1, size.width));
|
|
31413
|
-
const height = roundToLayoutPx(Math.max(1, size.height));
|
|
31414
31373
|
element.style.setProperty("box-sizing", "border-box");
|
|
31415
|
-
element.style.setProperty("width", `${width}px`);
|
|
31416
|
-
element.style.setProperty("height", `${height}px`);
|
|
31374
|
+
element.style.setProperty("width", `${size.width}px`);
|
|
31375
|
+
element.style.setProperty("height", `${size.height}px`);
|
|
31417
31376
|
element.style.setProperty("min-width", "0px");
|
|
31418
31377
|
element.style.setProperty("min-height", "0px");
|
|
31419
31378
|
element.style.setProperty("max-width", "none");
|
|
@@ -31428,6 +31387,7 @@ function applyStudioBoxSizeDimensions(element, size) {
|
|
|
31428
31387
|
if (computedDisplay === "inline") {
|
|
31429
31388
|
element.style.setProperty("display", "inline-block");
|
|
31430
31389
|
}
|
|
31390
|
+
return size;
|
|
31431
31391
|
}
|
|
31432
31392
|
function applyStudioBoxSize(element, size) {
|
|
31433
31393
|
promoteInlineForTransform(element);
|
|
@@ -31445,7 +31405,7 @@ function applyStudioBoxSizeDraft(element, size) {
|
|
|
31445
31405
|
boxSizeDraftBases.set(element, { width: element.offsetWidth, height: element.offsetHeight });
|
|
31446
31406
|
}
|
|
31447
31407
|
promoteInlineForTransform(element);
|
|
31448
|
-
applyStudioBoxSizeDimensions(element, size);
|
|
31408
|
+
return applyStudioBoxSizeDimensions(element, size);
|
|
31449
31409
|
}
|
|
31450
31410
|
function isSimpleRotateAngle(value) {
|
|
31451
31411
|
return /^-?(?:\d+(?:\.\d+)?|\.\d+)(?:deg|rad|turn|grad)$/.test(value.trim());
|
|
@@ -32184,7 +32144,7 @@ function getCachedProbe(url) {
|
|
|
32184
32144
|
return cached5?.result;
|
|
32185
32145
|
}
|
|
32186
32146
|
function resolveProbeSource(src, projectId) {
|
|
32187
|
-
return projectId ? resolveMediaPreviewUrl(src, projectId, window.location.origin) : src;
|
|
32147
|
+
return projectId ? resolveMediaPreviewUrl(authoredSrcPath(src), projectId, window.location.origin) : src;
|
|
32188
32148
|
}
|
|
32189
32149
|
function evictMetadataOverflow() {
|
|
32190
32150
|
const overflow = cache.size + failed.size - TIMELINE_VIEWPORT_BUDGETS.metadataRegistryEntries;
|
|
@@ -37615,7 +37575,7 @@ function OffCanvasIndicators({
|
|
|
37615
37575
|
const selectOffCanvas = async () => {
|
|
37616
37576
|
const el = elements.current.get(r.key);
|
|
37617
37577
|
if (!el) return;
|
|
37618
|
-
const { resolveDomEditSelection: resolveDomEditSelection2 } = await import("./domEditingLayers-
|
|
37578
|
+
const { resolveDomEditSelection: resolveDomEditSelection2 } = await import("./domEditingLayers-PYST4G45.js");
|
|
37619
37579
|
const acp = activeCompositionPathRef.current ?? "index.html";
|
|
37620
37580
|
const sel = await resolveDomEditSelection2(el, {
|
|
37621
37581
|
activeCompositionPath: acp,
|
|
@@ -37671,7 +37631,7 @@ function ChildRectOutlines({
|
|
|
37671
37631
|
|
|
37672
37632
|
// src/components/editor/domEditResizeLocal.ts
|
|
37673
37633
|
var MIN_RESIZE_LOCAL_PX = 1;
|
|
37674
|
-
var DEGENERATE_START_DIST_PX =
|
|
37634
|
+
var DEGENERATE_START_DIST_PX = 0.5;
|
|
37675
37635
|
function resolveCenterResizeScale(input) {
|
|
37676
37636
|
const startDist = Math.hypot(
|
|
37677
37637
|
input.pointerStart.x - input.centerStart.x,
|
|
@@ -37726,6 +37686,17 @@ function resolveRotatedResizeCursor(handle, rotationDeg) {
|
|
|
37726
37686
|
const bucket = Math.round(normalized / 45) % 8;
|
|
37727
37687
|
return CURSORS_8[bucket];
|
|
37728
37688
|
}
|
|
37689
|
+
function resizeRemainderShift(corners, grab, { wanted, written }) {
|
|
37690
|
+
const u = { x: corners.ne.x - corners.nw.x, y: corners.ne.y - corners.nw.y };
|
|
37691
|
+
const v = { x: corners.sw.x - corners.nw.x, y: corners.sw.y - corners.nw.y };
|
|
37692
|
+
const det = u.x * v.y - u.y * v.x;
|
|
37693
|
+
if (!det) return { x: 0, y: 0 };
|
|
37694
|
+
const su = Math.sign((grab.x * v.y - grab.y * v.x) / det);
|
|
37695
|
+
const sv = Math.sign((u.x * grab.y - u.y * grab.x) / det);
|
|
37696
|
+
const kw = su * (wanted.width - written.width) / (2 * written.width);
|
|
37697
|
+
const kh = sv * (wanted.height - written.height) / (2 * written.height);
|
|
37698
|
+
return { x: u.x * kw + v.x * kh, y: u.y * kw + v.y * kh };
|
|
37699
|
+
}
|
|
37729
37700
|
function computeNextResizeAnchor(prev, fixedStart, fixedNow) {
|
|
37730
37701
|
const base2 = prev ?? { dx: 0, dy: 0 };
|
|
37731
37702
|
return { dx: base2.dx + (fixedStart.x - fixedNow.x), dy: base2.dy + (fixedStart.y - fixedNow.y) };
|
|
@@ -39653,6 +39624,7 @@ function startGesture(kind, e, opts, options) {
|
|
|
39653
39624
|
manualEditDragToken,
|
|
39654
39625
|
snapContext,
|
|
39655
39626
|
resizeHandle: kind === "resize" ? options?.resizeHandle ?? "se" : void 0,
|
|
39627
|
+
resizePressFromCorner: kind === "resize" && options?.resizeCorner ? { x: e.clientX - options.resizeCorner.x, y: e.clientY - options.resizeCorner.y } : void 0,
|
|
39656
39628
|
resizeFixedCenterStart
|
|
39657
39629
|
};
|
|
39658
39630
|
if (kind === "resize") {
|
|
@@ -39746,7 +39718,7 @@ function createPreviewGestureStarts(opts, moveActiveGesture, releaseActiveGestur
|
|
|
39746
39718
|
offerUndo();
|
|
39747
39719
|
};
|
|
39748
39720
|
const drawPressedBox = (origin2) => origin2 && ((dx, dy) => opts.setOverlayRect(shiftedOverlayRect(origin2, dx, dy)));
|
|
39749
|
-
const drawResizedBox = (origin2,
|
|
39721
|
+
const drawResizedBox = (origin2, grabbed) => {
|
|
39750
39722
|
if (!origin2) return null;
|
|
39751
39723
|
const bounds = opts.overlayRef.current?.getBoundingClientRect();
|
|
39752
39724
|
const centre = {
|
|
@@ -39754,8 +39726,12 @@ function createPreviewGestureStarts(opts, moveActiveGesture, releaseActiveGestur
|
|
|
39754
39726
|
y: (bounds?.top ?? 0) + origin2.top + origin2.height / 2
|
|
39755
39727
|
};
|
|
39756
39728
|
return (dx, dy) => {
|
|
39757
|
-
const pointer = { x:
|
|
39758
|
-
const scale = resolveCenterResizeScale({
|
|
39729
|
+
const pointer = { x: grabbed.x + dx, y: grabbed.y + dy };
|
|
39730
|
+
const scale = resolveCenterResizeScale({
|
|
39731
|
+
pointer,
|
|
39732
|
+
pointerStart: grabbed,
|
|
39733
|
+
centerStart: centre
|
|
39734
|
+
});
|
|
39759
39735
|
const [width, height] = [origin2.width * scale, origin2.height * scale];
|
|
39760
39736
|
opts.setOverlayRect({
|
|
39761
39737
|
...origin2,
|
|
@@ -39874,7 +39850,10 @@ function createPreviewGestureStarts(opts, moveActiveGesture, releaseActiveGestur
|
|
|
39874
39850
|
let draw = null;
|
|
39875
39851
|
if (kind === "drag") draw = drawPressedBox(opts.overlayRectRef.current);
|
|
39876
39852
|
if (kind === "resize")
|
|
39877
|
-
draw = drawResizedBox(
|
|
39853
|
+
draw = drawResizedBox(
|
|
39854
|
+
opts.overlayRectRef.current,
|
|
39855
|
+
options?.resizeCorner ?? { x: e.clientX, y: e.clientY }
|
|
39856
|
+
);
|
|
39878
39857
|
return startOnShownPreview(
|
|
39879
39858
|
e,
|
|
39880
39859
|
() => {
|
|
@@ -39889,6 +39868,7 @@ function createPreviewGestureStarts(opts, moveActiveGesture, releaseActiveGestur
|
|
|
39889
39868
|
selection,
|
|
39890
39869
|
rect,
|
|
39891
39870
|
resizeHandle: options?.resizeHandle,
|
|
39871
|
+
resizeCorner: options?.resizeCorner,
|
|
39892
39872
|
at
|
|
39893
39873
|
});
|
|
39894
39874
|
},
|
|
@@ -39899,10 +39879,14 @@ function createPreviewGestureStarts(opts, moveActiveGesture, releaseActiveGestur
|
|
|
39899
39879
|
}
|
|
39900
39880
|
|
|
39901
39881
|
// src/components/editor/resizeDraft.ts
|
|
39902
|
-
function resolveResizeAnchor(g, corners, measureOrientedRect) {
|
|
39882
|
+
function resolveResizeAnchor(g, corners, measureOrientedRect, sizes) {
|
|
39903
39883
|
const fixedStart = g.resizeFixedCenterStart;
|
|
39904
39884
|
if (corners && fixedStart) {
|
|
39905
|
-
|
|
39885
|
+
const press = g.resizePressFromCorner ?? { x: 0, y: 0 };
|
|
39886
|
+
const grab = { x: g.startX - press.x - g.centerX, y: g.startY - press.y - g.centerY };
|
|
39887
|
+
const shift = resizeRemainderShift(corners, grab, sizes);
|
|
39888
|
+
const target = { x: fixedStart.x + shift.x, y: fixedStart.y + shift.y };
|
|
39889
|
+
return computeNextResizeAnchor(g.lastResizeAnchor, target, overlayCornersCentroid(corners));
|
|
39906
39890
|
}
|
|
39907
39891
|
const fallbackRect = measureOrientedRect();
|
|
39908
39892
|
return resolveResizeCenterAnchorOffset({
|
|
@@ -39912,9 +39896,9 @@ function resolveResizeAnchor(g, corners, measureOrientedRect) {
|
|
|
39912
39896
|
overlayHeight: fallbackRect ? fallbackRect.height : g.originHeight
|
|
39913
39897
|
});
|
|
39914
39898
|
}
|
|
39915
|
-
function resolveAnchoredResizeDraft(g, member, element, overlayEl, iframe, measureOrientedRect) {
|
|
39899
|
+
function resolveAnchoredResizeDraft(g, member, element, overlayEl, iframe, measureOrientedRect, sizes) {
|
|
39916
39900
|
const corners = overlayEl && iframe ? elementCornerOverlayPoints(overlayEl, iframe, element) : null;
|
|
39917
|
-
const anchor2 = resolveResizeAnchor(g, corners, measureOrientedRect);
|
|
39901
|
+
const anchor2 = resolveResizeAnchor(g, corners, measureOrientedRect, sizes);
|
|
39918
39902
|
g.lastResizeAnchor = anchor2;
|
|
39919
39903
|
applyManualOffsetDragDraft(member, anchor2.dx, anchor2.dy);
|
|
39920
39904
|
return measureOrientedRect() ?? {
|
|
@@ -39927,7 +39911,7 @@ function resolveAnchoredResizeDraft(g, member, element, overlayEl, iframe, measu
|
|
|
39927
39911
|
angle: g.actualRotation
|
|
39928
39912
|
};
|
|
39929
39913
|
}
|
|
39930
|
-
function resolveResizeDraftRect(g, element, overlayEl, iframe, measureOrientedRect) {
|
|
39914
|
+
function resolveResizeDraftRect(g, element, overlayEl, iframe, measureOrientedRect, sizes) {
|
|
39931
39915
|
if (g.pathOffsetMember) {
|
|
39932
39916
|
return resolveAnchoredResizeDraft(
|
|
39933
39917
|
g,
|
|
@@ -39935,7 +39919,8 @@ function resolveResizeDraftRect(g, element, overlayEl, iframe, measureOrientedRe
|
|
|
39935
39919
|
element,
|
|
39936
39920
|
overlayEl,
|
|
39937
39921
|
iframe,
|
|
39938
|
-
measureOrientedRect
|
|
39922
|
+
measureOrientedRect,
|
|
39923
|
+
sizes
|
|
39939
39924
|
);
|
|
39940
39925
|
}
|
|
39941
39926
|
return measureOrientedRect() ?? {
|
|
@@ -40260,14 +40245,15 @@ function createDomEditOverlayGestureHandlers(opts) {
|
|
|
40260
40245
|
}
|
|
40261
40246
|
if (g.pathOffsetMember) applyManualOffsetDragDraft(g.pathOffsetMember, dx, dy);
|
|
40262
40247
|
} else {
|
|
40248
|
+
const grab = g.resizePressFromCorner ?? { x: 0, y: 0 };
|
|
40263
40249
|
const nextSize = resolveCenterResizeSize({
|
|
40264
40250
|
baseWidth: g.actualWidth,
|
|
40265
40251
|
baseHeight: g.actualHeight,
|
|
40266
|
-
pointer: { x: e.clientX, y: e.clientY },
|
|
40267
|
-
pointerStart: { x: g.startX, y: g.startY },
|
|
40252
|
+
pointer: { x: e.clientX - grab.x, y: e.clientY - grab.y },
|
|
40253
|
+
pointerStart: { x: g.startX - grab.x, y: g.startY - grab.y },
|
|
40268
40254
|
centerStart: { x: g.centerX, y: g.centerY }
|
|
40269
40255
|
});
|
|
40270
|
-
applyStudioBoxSizeDraft(sel.element, nextSize);
|
|
40256
|
+
const writtenSize = applyStudioBoxSizeDraft(sel.element, nextSize);
|
|
40271
40257
|
const overlayEl = opts.overlayRef.current;
|
|
40272
40258
|
const iframe = opts.iframeRef.current;
|
|
40273
40259
|
const measureOrientedRect = () => overlayEl && iframe ? orientedOverlayRect(overlayEl, iframe, sel.element) : null;
|
|
@@ -40276,7 +40262,8 @@ function createDomEditOverlayGestureHandlers(opts) {
|
|
|
40276
40262
|
sel.element,
|
|
40277
40263
|
overlayEl,
|
|
40278
40264
|
iframe,
|
|
40279
|
-
measureOrientedRect
|
|
40265
|
+
measureOrientedRect,
|
|
40266
|
+
{ wanted: nextSize, written: writtenSize }
|
|
40280
40267
|
);
|
|
40281
40268
|
logResizeMove({
|
|
40282
40269
|
pointer: { x: e.clientX, y: e.clientY },
|
|
@@ -41353,13 +41340,22 @@ var RESIZE_HANDLE_DEFS = [
|
|
|
41353
41340
|
{ handle: "se", cursor: "nwse-resize", x: "right", y: "bottom" }
|
|
41354
41341
|
];
|
|
41355
41342
|
var NO_CROP_INSET = { top: 0, right: 0, bottom: 0, left: 0 };
|
|
41356
|
-
function
|
|
41343
|
+
function resizeHandleLayout(def, overlayRect, cropInset) {
|
|
41357
41344
|
const half = RESIZE_HANDLE_HIT_PX / 2;
|
|
41358
41345
|
const inset = cropInset ?? NO_CROP_INSET;
|
|
41359
|
-
const
|
|
41360
|
-
|
|
41361
|
-
|
|
41362
|
-
|
|
41346
|
+
const cornerX = def.x === "left" ? overlayRect.left + inset.left : overlayRect.left + overlayRect.width - inset.right;
|
|
41347
|
+
const cornerY = def.y === "top" ? overlayRect.top + inset.top : overlayRect.top + overlayRect.height - inset.bottom;
|
|
41348
|
+
const slideOutToFreeMiddleX = (def.x === "left" ? -1 : 1) * Math.max(0, half - (overlayRect.width - inset.left - inset.right) / 4);
|
|
41349
|
+
const slideOutToFreeMiddleY = (def.y === "top" ? -1 : 1) * Math.max(0, half - (overlayRect.height - inset.top - inset.bottom) / 4);
|
|
41350
|
+
return {
|
|
41351
|
+
style: {
|
|
41352
|
+
cursor: def.cursor,
|
|
41353
|
+
touchAction: "none",
|
|
41354
|
+
left: cornerX - half + slideOutToFreeMiddleX,
|
|
41355
|
+
top: cornerY - half + slideOutToFreeMiddleY
|
|
41356
|
+
},
|
|
41357
|
+
anchor: { left: half - slideOutToFreeMiddleX, top: half - slideOutToFreeMiddleY }
|
|
41358
|
+
};
|
|
41363
41359
|
}
|
|
41364
41360
|
function DomEditGroupChrome({
|
|
41365
41361
|
groupOverlayItems,
|
|
@@ -41491,26 +41487,42 @@ function DomEditSelectionChrome({
|
|
|
41491
41487
|
},
|
|
41492
41488
|
selectionKey
|
|
41493
41489
|
),
|
|
41494
|
-
canManipulate && !editing && selection.capabilities.canApplyManualSize && RESIZE_HANDLE_DEFS.map(
|
|
41495
|
-
(def
|
|
41490
|
+
canManipulate && !editing && selection.capabilities.canApplyManualSize && RESIZE_HANDLE_DEFS.map((def) => {
|
|
41491
|
+
if (def.handle !== "se" && !selection.capabilities.canApplyManualOffset) return null;
|
|
41492
|
+
const layout = resizeHandleLayout(def, overlayRect, cropOutlineInsetPx ?? void 0);
|
|
41493
|
+
return /* @__PURE__ */ jsxs69(
|
|
41496
41494
|
"div",
|
|
41497
41495
|
{
|
|
41498
41496
|
className: "pointer-events-auto absolute flex h-4 w-4 items-center justify-center",
|
|
41499
41497
|
style: {
|
|
41500
|
-
...
|
|
41498
|
+
...layout.style,
|
|
41501
41499
|
// Cursor rotates with the object: bucket the corner's base
|
|
41502
41500
|
// diagonal + element rotation into the 8 CSS resize cursors.
|
|
41503
41501
|
cursor: resolveRotatedResizeCursor(def.handle, overlayRect.angle ?? 0)
|
|
41504
41502
|
},
|
|
41505
41503
|
onPointerDown: (e) => {
|
|
41506
41504
|
e.stopPropagation();
|
|
41507
|
-
|
|
41505
|
+
const corner = e.currentTarget.querySelector("[data-resize-corner]")?.getBoundingClientRect();
|
|
41506
|
+
gestures.startGesture("resize", e, {
|
|
41507
|
+
resizeHandle: def.handle,
|
|
41508
|
+
resizeCorner: corner && { x: corner.left, y: corner.top }
|
|
41509
|
+
});
|
|
41508
41510
|
},
|
|
41509
|
-
children:
|
|
41511
|
+
children: [
|
|
41512
|
+
/* @__PURE__ */ jsx99(
|
|
41513
|
+
"span",
|
|
41514
|
+
{
|
|
41515
|
+
"data-resize-corner": true,
|
|
41516
|
+
className: "pointer-events-none absolute",
|
|
41517
|
+
style: layout.anchor
|
|
41518
|
+
}
|
|
41519
|
+
),
|
|
41520
|
+
/* @__PURE__ */ jsx99("div", { className: "pointer-events-none h-[12px] w-[12px] rounded-full border-[1.5px] border-studio-accent bg-white shadow-[0_0_3px_rgba(0,0,0,0.45)]" })
|
|
41521
|
+
]
|
|
41510
41522
|
},
|
|
41511
41523
|
def.handle
|
|
41512
|
-
)
|
|
41513
|
-
)
|
|
41524
|
+
);
|
|
41525
|
+
})
|
|
41514
41526
|
]
|
|
41515
41527
|
}
|
|
41516
41528
|
),
|
|
@@ -52882,7 +52894,11 @@ function trimFractions(el) {
|
|
|
52882
52894
|
return { start, end };
|
|
52883
52895
|
}
|
|
52884
52896
|
function renderAudioClip(el, pid, sessionEpoch, labelColor, context, elements, labelInset) {
|
|
52885
|
-
const audioUrl = resolveMediaPreviewUrl(
|
|
52897
|
+
const audioUrl = resolveMediaPreviewUrl(
|
|
52898
|
+
authoredSrcPath(el.src ?? ""),
|
|
52899
|
+
pid,
|
|
52900
|
+
window.location.origin
|
|
52901
|
+
);
|
|
52886
52902
|
const srcRelative = resolvePreviewRelative(audioUrl, pid, window.location.origin);
|
|
52887
52903
|
const encodedRelative = srcRelative ? encodePreviewPath(srcRelative) : null;
|
|
52888
52904
|
const waveformUrl = encodedRelative ? buildProjectApiPath(pid, `/waveform/${encodedRelative}`) : void 0;
|
|
@@ -52982,7 +52998,11 @@ function useRenderClipContent({
|
|
|
52982
52998
|
}
|
|
52983
52999
|
const htmlPreviewEligible = el.duration > 0 && effectiveTimelineDuration > 0;
|
|
52984
53000
|
if ((el.tag === "video" || el.tag === "img") && el.src) {
|
|
52985
|
-
const mediaSrc = resolveMediaPreviewUrl(
|
|
53001
|
+
const mediaSrc = resolveMediaPreviewUrl(
|
|
53002
|
+
authoredSrcPath(el.src),
|
|
53003
|
+
pid,
|
|
53004
|
+
window.location.origin
|
|
53005
|
+
);
|
|
52986
53006
|
if (el.tag === "img") {
|
|
52987
53007
|
return createElement(ImageThumbnail, {
|
|
52988
53008
|
imageSrc: mediaSrc,
|
|
@@ -54700,8 +54720,8 @@ function MediaSection({
|
|
|
54700
54720
|
const [removeProgress, setRemoveProgress] = useState65(null);
|
|
54701
54721
|
const [createPlate, setCreatePlate] = useState65(false);
|
|
54702
54722
|
const [quality, setQuality] = useState65("balanced");
|
|
54703
|
-
const
|
|
54704
|
-
const
|
|
54723
|
+
const projectSrc = srcAttr && !/^(?:https?:|data:|blob:)/i.test(srcAttr) ? authoredSrcPath(srcAttr.startsWith("./") ? srcAttr.slice(2) : srcAttr) : "";
|
|
54724
|
+
const absoluteSrc = projectDir && projectSrc ? `${projectDir}/${projectSrc}` : srcAttr;
|
|
54705
54725
|
const canRemoveBackground = Boolean(onRemoveBackground && isVisualMedia && projectSrc);
|
|
54706
54726
|
const panelTitle = isImage ? "Image" : isVideo ? "Video" : "Audio";
|
|
54707
54727
|
useEffect72(() => {
|
|
@@ -56024,7 +56044,7 @@ function resolveProjectAssetPath(sourceFile, src, projectId) {
|
|
|
56024
56044
|
return stripPreviewAssetPath(trimmed, projectId);
|
|
56025
56045
|
}
|
|
56026
56046
|
const sourceDir = sourceFile.includes("/") ? sourceFile.slice(0, sourceFile.lastIndexOf("/")) : "";
|
|
56027
|
-
const parts = `${sourceDir}/${trimmed}`.split("/");
|
|
56047
|
+
const parts = `${sourceDir}/${authoredSrcPath(trimmed)}`.split("/");
|
|
56028
56048
|
const normalized = [];
|
|
56029
56049
|
for (const part of parts) {
|
|
56030
56050
|
if (!part || part === ".") continue;
|
|
@@ -58498,6 +58518,7 @@ function ReverseGradientIcon({ size = 16 }) {
|
|
|
58498
58518
|
}
|
|
58499
58519
|
|
|
58500
58520
|
// src/components/editor/propertyPanelFill.tsx
|
|
58521
|
+
import { encodeUrlPath as encodeUrlPath3 } from "@hyperframes/parsers";
|
|
58501
58522
|
import { jsx as jsx137, jsxs as jsxs99 } from "react/jsx-runtime";
|
|
58502
58523
|
function normalizeProjectPath(value) {
|
|
58503
58524
|
const trimmed = value.trim();
|
|
@@ -58624,7 +58645,7 @@ function ImageFillField({
|
|
|
58624
58645
|
selectedAsset && /* @__PURE__ */ jsx137("div", { className: "overflow-hidden rounded-xl border border-neutral-800 bg-neutral-900/80", children: /* @__PURE__ */ jsx137(
|
|
58625
58646
|
"img",
|
|
58626
58647
|
{
|
|
58627
|
-
src: buildProjectApiPath(projectId, `/preview/${selectedAsset}`),
|
|
58648
|
+
src: buildProjectApiPath(projectId, `/preview/${encodeUrlPath3(selectedAsset)}`),
|
|
58628
58649
|
alt: selectedAsset.split("/").pop() ?? selectedAsset,
|
|
58629
58650
|
className: "h-28 w-full object-contain bg-neutral-950/80"
|
|
58630
58651
|
}
|
|
@@ -67090,8 +67111,8 @@ function FlatMediaSection({
|
|
|
67090
67111
|
const [removeProgress, setRemoveProgress] = useState94(null);
|
|
67091
67112
|
const [createPlate, setCreatePlate] = useState94(false);
|
|
67092
67113
|
const [quality, setQuality] = useState94("balanced");
|
|
67093
|
-
const
|
|
67094
|
-
const
|
|
67114
|
+
const projectSrc = srcAttr && !/^(?:https?:|data:|blob:)/i.test(srcAttr) ? authoredSrcPath(srcAttr.startsWith("./") ? srcAttr.slice(2) : srcAttr) : "";
|
|
67115
|
+
const absoluteSrc = projectDir && projectSrc ? `${projectDir}/${projectSrc}` : srcAttr;
|
|
67095
67116
|
const canRemoveBackground = Boolean(onRemoveBackground && isVisualMedia && projectSrc);
|
|
67096
67117
|
useEffect94(() => {
|
|
67097
67118
|
setRemoveProgress(null);
|
|
@@ -75118,6 +75139,7 @@ import { useState as useState117, useCallback as useCallback104, useRef as useRe
|
|
|
75118
75139
|
|
|
75119
75140
|
// src/hooks/useFileTree.ts
|
|
75120
75141
|
import { useState as useState116, useCallback as useCallback101, useEffect as useEffect113, useMemo as useMemo71, useRef as useRef128 } from "react";
|
|
75142
|
+
import { encodeUrlPath as encodeUrlPath4 } from "@hyperframes/parsers";
|
|
75121
75143
|
var EMPTY_FILE_LIST = [];
|
|
75122
75144
|
function useFileTree({ projectId, projectIdRef }) {
|
|
75123
75145
|
const [fetched, setFetched] = useState116(null);
|
|
@@ -75189,7 +75211,7 @@ function useFileTree({ projectId, projectIdRef }) {
|
|
|
75189
75211
|
() => (projectId ? assets : []).filter((asset) => FONT_EXT.test(asset)).map((asset) => ({
|
|
75190
75212
|
family: fontFamilyFromAssetPath(asset),
|
|
75191
75213
|
path: asset,
|
|
75192
|
-
url: projectId ? buildProjectApiPath(projectId, `/preview/${asset}`) : ""
|
|
75214
|
+
url: projectId ? buildProjectApiPath(projectId, `/preview/${encodeUrlPath4(asset)}`) : ""
|
|
75193
75215
|
})),
|
|
75194
75216
|
[assets, projectId]
|
|
75195
75217
|
);
|
|
@@ -75454,6 +75476,7 @@ function useProjectFileWriter({ projectId }) {
|
|
|
75454
75476
|
}
|
|
75455
75477
|
|
|
75456
75478
|
// src/hooks/useFileManager.ts
|
|
75479
|
+
import { encodeUrlPath as encodeUrlPath5 } from "@hyperframes/parsers";
|
|
75457
75480
|
function useFileManager({
|
|
75458
75481
|
projectId,
|
|
75459
75482
|
showToast,
|
|
@@ -75763,7 +75786,7 @@ function useFileManager({
|
|
|
75763
75786
|
const imported = uploaded.filter((asset) => FONT_EXT.test(asset)).map((asset) => ({
|
|
75764
75787
|
family: fontFamilyFromAssetPath(asset),
|
|
75765
75788
|
path: asset,
|
|
75766
|
-
url: `/api/projects/${encodeURIComponent(pid)}/preview/${asset}`
|
|
75789
|
+
url: `/api/projects/${encodeURIComponent(pid)}/preview/${encodeUrlPath5(asset)}`
|
|
75767
75790
|
}));
|
|
75768
75791
|
importedFontAssetsRef.current = [
|
|
75769
75792
|
...imported,
|
|
@@ -81799,6 +81822,7 @@ function useDomGeometryCommits({
|
|
|
81799
81822
|
}
|
|
81800
81823
|
|
|
81801
81824
|
// src/hooks/useDomEditCommits.ts
|
|
81825
|
+
import { encodeUrlPath as encodeUrlPath6 } from "@hyperframes/parsers";
|
|
81802
81826
|
function useDomEditCommits({
|
|
81803
81827
|
activeCompPath,
|
|
81804
81828
|
previewIframeRef,
|
|
@@ -81837,7 +81861,7 @@ function useDomEditCommits({
|
|
|
81837
81861
|
return {
|
|
81838
81862
|
family: fontFamilyFromAssetPath(asset),
|
|
81839
81863
|
path: asset,
|
|
81840
|
-
url: buildProjectApiPath(projectId, `/preview/${asset}`)
|
|
81864
|
+
url: buildProjectApiPath(projectId, `/preview/${encodeUrlPath6(asset)}`)
|
|
81841
81865
|
};
|
|
81842
81866
|
},
|
|
81843
81867
|
[fileTree, projectId, importedFontAssetsRef]
|
|
@@ -84815,6 +84839,9 @@ function tweenUsesScaleLonghands(anim) {
|
|
|
84815
84839
|
);
|
|
84816
84840
|
return inKeyframes || Object.keys(anim?.properties ?? {}).some(isLonghand);
|
|
84817
84841
|
}
|
|
84842
|
+
function rectCentre(rect) {
|
|
84843
|
+
return { x: rect.x + rect.width / 2, y: rect.y + rect.height / 2 };
|
|
84844
|
+
}
|
|
84818
84845
|
async function tryGsapResizeIntercept(selection, size, animations, iframe, commitMutation, fetchFallbackAnimations, dragOffset, draw = (run) => run(), stamp) {
|
|
84819
84846
|
const moment = editMoment(stamp);
|
|
84820
84847
|
const fetchedAnimations = fetchFallbackAnimations ? await fetchFallbackAnimations() : [];
|
|
@@ -84929,8 +84956,7 @@ async function tryGsapResizeIntercept(selection, size, animations, iframe, commi
|
|
|
84929
84956
|
scaleDraftEl = el;
|
|
84930
84957
|
committedScale = useScaleLonghands ? { x: newScaleX, y: newScaleY } : { x: newScaleX, y: newScaleX };
|
|
84931
84958
|
if (el) {
|
|
84932
|
-
|
|
84933
|
-
scaleDraftDropPoint = { x: dropRect.x, y: dropRect.y };
|
|
84959
|
+
scaleDraftDropPoint = draw(() => rectCentre(el.getBoundingClientRect()));
|
|
84934
84960
|
}
|
|
84935
84961
|
} else {
|
|
84936
84962
|
resizeProps = {
|
|
@@ -84961,31 +84987,31 @@ async function tryGsapResizeIntercept(selection, size, animations, iframe, commi
|
|
|
84961
84987
|
);
|
|
84962
84988
|
const base3 = { x: baseGsapX, y: baseGsapY };
|
|
84963
84989
|
setElementGsapPosition(draftEl, base3.x, base3.y);
|
|
84964
|
-
const post2 = draftEl.getBoundingClientRect();
|
|
84965
|
-
const
|
|
84966
|
-
if (!Number.isFinite(
|
|
84967
|
-
if (Math.abs(residual.x) < 0.5 && Math.abs(residual.y) < 0.5) {
|
|
84968
|
-
logResize("scale-finalize", { skipped: "already-on-drop-point", residual, base: base3 });
|
|
84969
|
-
return "settled";
|
|
84970
|
-
}
|
|
84990
|
+
const post2 = rectCentre(draftEl.getBoundingClientRect());
|
|
84991
|
+
const residual2 = { x: dropPoint.x - post2.x, y: dropPoint.y - post2.y };
|
|
84992
|
+
if (!Number.isFinite(residual2.x) || !Number.isFinite(residual2.y)) return null;
|
|
84971
84993
|
const corrected2 = {
|
|
84972
|
-
x: roundTo3(base3.x +
|
|
84973
|
-
y: roundTo3(base3.y +
|
|
84994
|
+
x: roundTo3(base3.x + residual2.x),
|
|
84995
|
+
y: roundTo3(base3.y + residual2.y)
|
|
84974
84996
|
};
|
|
84997
|
+
if (corrected2.x === roundTo3(base3.x) && corrected2.y === roundTo3(base3.y)) {
|
|
84998
|
+
logResize("scale-finalize", { skipped: "already-on-drop-point", residual: residual2, base: base3 });
|
|
84999
|
+
return "settled";
|
|
85000
|
+
}
|
|
84975
85001
|
logResize("scale-finalize", {
|
|
84976
85002
|
dropPoint,
|
|
84977
|
-
post:
|
|
84978
|
-
residual,
|
|
85003
|
+
post: post2,
|
|
85004
|
+
residual: residual2,
|
|
84979
85005
|
gsapPos,
|
|
84980
85006
|
base: base3,
|
|
84981
85007
|
corrected: corrected2
|
|
84982
85008
|
});
|
|
84983
85009
|
setElementGsapPosition(draftEl, corrected2.x, corrected2.y);
|
|
84984
|
-
return { base: base3, corrected: corrected2 };
|
|
85010
|
+
return { base: base3, corrected: corrected2, residual: residual2 };
|
|
84985
85011
|
});
|
|
84986
85012
|
if (measured === null) return false;
|
|
84987
85013
|
if (measured === "settled") return true;
|
|
84988
|
-
const { base: base2, corrected } = measured;
|
|
85014
|
+
const { base: base2, corrected, residual } = measured;
|
|
84989
85015
|
const currentAnimations = fetchFallbackAnimations ? await fetchFallbackAnimations() : resolved2?.animations ?? animations;
|
|
84990
85016
|
const delta = { x: corrected.x - base2.x, y: corrected.y - base2.y };
|
|
84991
85017
|
const positionTween = pickClosestToPlayhead(
|
|
@@ -84995,6 +85021,10 @@ async function tryGsapResizeIntercept(selection, size, animations, iframe, commi
|
|
|
84995
85021
|
moment.time
|
|
84996
85022
|
);
|
|
84997
85023
|
if (positionTween) {
|
|
85024
|
+
if (Math.abs(residual.x) < 0.5 && Math.abs(residual.y) < 0.5) {
|
|
85025
|
+
draw(() => setElementGsapPosition(draftEl, base2.x, base2.y));
|
|
85026
|
+
return true;
|
|
85027
|
+
}
|
|
84998
85028
|
logResize("scale-finalize", { route: "position-keyframe", tweenId: positionTween.id });
|
|
84999
85029
|
assertGsapEditPersisted(
|
|
85000
85030
|
await commitGsapPositionFromDrag(selection, positionTween, delta, base2, iframe, {
|
|
@@ -91352,6 +91382,7 @@ import { memo as memo50, useCallback as useCallback171 } from "react";
|
|
|
91352
91382
|
|
|
91353
91383
|
// src/components/MediaPreview.tsx
|
|
91354
91384
|
import { useState as useState136 } from "react";
|
|
91385
|
+
import { encodeUrlPath as encodeUrlPath7 } from "@hyperframes/parsers";
|
|
91355
91386
|
import { jsx as jsx212, jsxs as jsxs166 } from "react/jsx-runtime";
|
|
91356
91387
|
function MediaErrorPanel({ name, filePath }) {
|
|
91357
91388
|
return /* @__PURE__ */ jsxs166("div", { className: "flex flex-col items-center justify-center h-full p-4 bg-neutral-950 gap-2", children: [
|
|
@@ -91379,7 +91410,7 @@ function MediaErrorPanel({ name, filePath }) {
|
|
|
91379
91410
|
] });
|
|
91380
91411
|
}
|
|
91381
91412
|
function MediaPreview({ projectId, filePath }) {
|
|
91382
|
-
const serveUrl = buildProjectApiPath(projectId, `/preview/${filePath}`);
|
|
91413
|
+
const serveUrl = buildProjectApiPath(projectId, `/preview/${encodeUrlPath7(filePath)}`);
|
|
91383
91414
|
const name = filePath.split("/").pop() ?? filePath;
|
|
91384
91415
|
const [failedPath, setFailedPath] = useState136(null);
|
|
91385
91416
|
const failed2 = failedPath === filePath;
|