@hyperframes/studio 0.6.28 → 0.6.29
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/{index-EdfhuQ5T.js → index-C-kAqQVb.js} +52 -52
- package/dist/index.html +1 -1
- package/package.json +4 -4
- package/src/components/editor/domEditingLayers.ts +15 -4
- package/src/components/editor/domEditingTypes.ts +1 -0
- package/src/player/components/timelineEditing.test.ts +16 -0
- package/src/player/components/timelineEditing.ts +2 -1
- package/src/player/lib/timelineDOM.ts +4 -0
- package/src/player/store/playerStore.ts +2 -0
package/dist/index.html
CHANGED
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
<meta name="viewport" content="width=device-width, initial-scale=1.0, viewport-fit=cover" />
|
|
6
6
|
<link rel="icon" type="image/svg+xml" href="/favicon.svg" />
|
|
7
7
|
<title>HyperFrames Studio</title>
|
|
8
|
-
<script type="module" crossorigin src="/assets/index-
|
|
8
|
+
<script type="module" crossorigin src="/assets/index-C-kAqQVb.js"></script>
|
|
9
9
|
<link rel="stylesheet" crossorigin href="/assets/index-DVpLGNHi.css">
|
|
10
10
|
</head>
|
|
11
11
|
<body>
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@hyperframes/studio",
|
|
3
|
-
"version": "0.6.
|
|
3
|
+
"version": "0.6.29",
|
|
4
4
|
"description": "",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -31,8 +31,8 @@
|
|
|
31
31
|
"@codemirror/view": "6.40.0",
|
|
32
32
|
"@phosphor-icons/react": "^2.1.10",
|
|
33
33
|
"mediabunny": "^1.45.3",
|
|
34
|
-
"@hyperframes/core": "0.6.
|
|
35
|
-
"@hyperframes/player": "0.6.
|
|
34
|
+
"@hyperframes/core": "0.6.29",
|
|
35
|
+
"@hyperframes/player": "0.6.29"
|
|
36
36
|
},
|
|
37
37
|
"devDependencies": {
|
|
38
38
|
"@types/react": "19",
|
|
@@ -46,7 +46,7 @@
|
|
|
46
46
|
"vite": "^6.4.2",
|
|
47
47
|
"vitest": "^3.2.4",
|
|
48
48
|
"zustand": "^5.0.0",
|
|
49
|
-
"@hyperframes/producer": "0.6.
|
|
49
|
+
"@hyperframes/producer": "0.6.29"
|
|
50
50
|
},
|
|
51
51
|
"peerDependencies": {
|
|
52
52
|
"react": "19",
|
|
@@ -12,6 +12,7 @@ import type {
|
|
|
12
12
|
} from "./domEditingTypes";
|
|
13
13
|
import {
|
|
14
14
|
buildStableSelector,
|
|
15
|
+
findClosestByAttribute,
|
|
15
16
|
getCuratedComputedStyles,
|
|
16
17
|
getDataAttributes,
|
|
17
18
|
getInlineStyles,
|
|
@@ -175,18 +176,21 @@ export function resolveDomEditCapabilities(args: {
|
|
|
175
176
|
inlineStyles: Record<string, string>;
|
|
176
177
|
computedStyles: Record<string, string>;
|
|
177
178
|
isCompositionHost: boolean;
|
|
179
|
+
isInsideLockedComposition: boolean;
|
|
178
180
|
isMasterView: boolean;
|
|
179
181
|
}): DomEditCapabilities {
|
|
180
|
-
if (!args.selector) {
|
|
182
|
+
if (!args.selector || args.isInsideLockedComposition) {
|
|
181
183
|
return {
|
|
182
|
-
canSelect:
|
|
184
|
+
canSelect: !args.isInsideLockedComposition,
|
|
183
185
|
canEditStyles: false,
|
|
184
186
|
canMove: false,
|
|
185
187
|
canResize: false,
|
|
186
188
|
canApplyManualOffset: false,
|
|
187
189
|
canApplyManualSize: false,
|
|
188
190
|
canApplyManualRotation: false,
|
|
189
|
-
reasonIfDisabled:
|
|
191
|
+
reasonIfDisabled: args.isInsideLockedComposition
|
|
192
|
+
? "This element belongs to a locked composition."
|
|
193
|
+
: "Studio could not resolve a stable patch target for this element.",
|
|
190
194
|
};
|
|
191
195
|
}
|
|
192
196
|
|
|
@@ -298,6 +302,7 @@ export function resolveDomEditSelection(
|
|
|
298
302
|
const inlineStyles = getInlineStyles(current);
|
|
299
303
|
const computedStyles = getCuratedComputedStyles(current);
|
|
300
304
|
const textFields = collectDomEditTextFields(current);
|
|
305
|
+
const isInsideLocked = Boolean(findClosestByAttribute(current, ["data-timeline-locked"]));
|
|
301
306
|
const capabilities = resolveDomEditCapabilities({
|
|
302
307
|
selector,
|
|
303
308
|
tagName: current.tagName.toLowerCase(),
|
|
@@ -305,6 +310,7 @@ export function resolveDomEditSelection(
|
|
|
305
310
|
inlineStyles,
|
|
306
311
|
computedStyles,
|
|
307
312
|
isCompositionHost: Boolean(compositionSrc),
|
|
313
|
+
isInsideLockedComposition: isInsideLocked,
|
|
308
314
|
isMasterView: options.isMasterView,
|
|
309
315
|
});
|
|
310
316
|
const rect = current.getBoundingClientRect();
|
|
@@ -318,6 +324,7 @@ export function resolveDomEditSelection(
|
|
|
318
324
|
compositionPath,
|
|
319
325
|
compositionSrc,
|
|
320
326
|
isCompositionHost: Boolean(compositionSrc),
|
|
327
|
+
isInsideLockedComposition: isInsideLocked,
|
|
321
328
|
label: buildElementLabel(current),
|
|
322
329
|
tagName: current.tagName.toLowerCase(),
|
|
323
330
|
boundingBox: {
|
|
@@ -488,7 +495,11 @@ export function getDomEditTargetKey(
|
|
|
488
495
|
}
|
|
489
496
|
|
|
490
497
|
export function isTextEditableSelection(selection: DomEditSelection): boolean {
|
|
491
|
-
return
|
|
498
|
+
return (
|
|
499
|
+
selection.textFields.length > 0 &&
|
|
500
|
+
!selection.isCompositionHost &&
|
|
501
|
+
!selection.isInsideLockedComposition
|
|
502
|
+
);
|
|
492
503
|
}
|
|
493
504
|
|
|
494
505
|
// buildElementAgentPrompt is in domEditingAgentPrompt.ts
|
|
@@ -78,6 +78,7 @@ export interface DomEditSelection extends PatchTarget {
|
|
|
78
78
|
compositionPath: string;
|
|
79
79
|
compositionSrc?: string;
|
|
80
80
|
isCompositionHost: boolean;
|
|
81
|
+
isInsideLockedComposition: boolean;
|
|
81
82
|
boundingBox: { x: number; y: number; width: number; height: number };
|
|
82
83
|
textContent: string | null;
|
|
83
84
|
dataAttributes: Record<string, string>;
|
|
@@ -263,6 +263,22 @@ describe("getTimelineEditCapabilities", () => {
|
|
|
263
263
|
});
|
|
264
264
|
});
|
|
265
265
|
|
|
266
|
+
it("locks all timeline edits for clips with data-timeline-locked", () => {
|
|
267
|
+
expect(
|
|
268
|
+
getTimelineEditCapabilities({
|
|
269
|
+
tag: "div",
|
|
270
|
+
duration: 8,
|
|
271
|
+
selector: '[data-composition-id="caption-highlight"]',
|
|
272
|
+
compositionSrc: "compositions/components/caption-highlight.html",
|
|
273
|
+
timelineLocked: true,
|
|
274
|
+
}),
|
|
275
|
+
).toEqual({
|
|
276
|
+
canMove: false,
|
|
277
|
+
canTrimStart: false,
|
|
278
|
+
canTrimEnd: false,
|
|
279
|
+
});
|
|
280
|
+
});
|
|
281
|
+
|
|
266
282
|
it("allows full editing of explicitly authored generic elements", () => {
|
|
267
283
|
expect(
|
|
268
284
|
getTimelineEditCapabilities({
|
|
@@ -211,8 +211,9 @@ export function getTimelineEditCapabilities(input: {
|
|
|
211
211
|
playbackStartAttr?: "media-start" | "playback-start";
|
|
212
212
|
sourceDuration?: number;
|
|
213
213
|
timingSource?: "authored" | "implicit";
|
|
214
|
+
timelineLocked?: boolean;
|
|
214
215
|
}): TimelineEditCapabilities {
|
|
215
|
-
if (input.timingSource === "implicit") {
|
|
216
|
+
if (input.timingSource === "implicit" || input.timelineLocked) {
|
|
216
217
|
return {
|
|
217
218
|
canMove: false,
|
|
218
219
|
canTrimStart: false,
|
|
@@ -280,6 +280,10 @@ export function parseTimelineFromDOM(doc: Document, rootDuration: number): Timel
|
|
|
280
280
|
applyMediaMetadataFromElement(entry, el);
|
|
281
281
|
}
|
|
282
282
|
|
|
283
|
+
if (el.hasAttribute("data-timeline-locked")) {
|
|
284
|
+
entry.timelineLocked = true;
|
|
285
|
+
}
|
|
286
|
+
|
|
283
287
|
// Sub-compositions
|
|
284
288
|
const compSrc =
|
|
285
289
|
el.getAttribute("data-composition-src") || el.getAttribute("data-composition-file");
|
|
@@ -26,6 +26,8 @@ export interface TimelineElement {
|
|
|
26
26
|
compositionSrc?: string;
|
|
27
27
|
/** Whether this row came from authored clip timing or Studio's full-duration layer fallback. */
|
|
28
28
|
timingSource?: "authored" | "implicit";
|
|
29
|
+
/** Set by data-timeline-locked on the host element — disables move and trim in Studio. */
|
|
30
|
+
timelineLocked?: boolean;
|
|
29
31
|
}
|
|
30
32
|
|
|
31
33
|
export type ZoomMode = "fit" | "manual";
|