@hyperframes/studio 0.8.137 → 0.8.139
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-D_Mh6hbx.js → hyperframes-player-CckOoCJ8.js} +1 -1
- package/dist/assets/{index-CHEctGzc.js → index-BmIPrb8I.js} +1 -1
- package/dist/assets/{index-B3lJsA-e.js → index-Br1Whc0f.js} +189 -189
- package/dist/assets/{index-CC_E-Cbl.css → index-CVd4O6eH.css} +1 -1
- package/dist/assets/{index-rtccfg9b.js → index-DsEkE5_G.js} +1 -1
- package/dist/{chunk-4S3AYCOG.js → chunk-E422JDF5.js} +2 -2
- package/dist/{chunk-TDWGXBUT.js → chunk-TFLU2MGI.js} +1 -6
- package/dist/chunk-TFLU2MGI.js.map +1 -0
- package/dist/{chunk-7UQWVN52.js → chunk-UYWON5AX.js} +2 -2
- package/dist/{domEditingLayers-IEVLO54Z.js → domEditingLayers-KBTPQKGA.js} +3 -3
- package/dist/index.d.ts +2 -1
- package/dist/index.html +2 -2
- package/dist/index.js +867 -499
- package/dist/index.js.map +1 -1
- package/dist/player.js +2 -2
- package/dist/styles.css +1 -1
- package/package.json +9 -8
- package/src/App.tsx +11 -11
- package/src/components/editor/DomEditOverlay.tsx +9 -5
- package/src/components/editor/LayersPanel.test.ts +25 -0
- package/src/components/editor/LayersPanel.tsx +1 -1
- package/src/components/editor/PropertyPanel.test.tsx +600 -748
- package/src/components/editor/anchoredResizeCommitFeedsOffset.test.ts +2 -0
- package/src/components/editor/domEditOverlayGeometry.ts +7 -7
- package/src/components/editor/domEditOverlayGestures.ts +18 -0
- package/src/components/editor/domEditOverlayStartGesture.blocked.test.ts +1 -0
- package/src/components/editor/domEditOverlayStartGesture.test.ts +3 -0
- package/src/components/editor/domEditOverlayStartGesture.ts +9 -1
- package/src/components/editor/dragUndoPaint.test.ts +2 -0
- package/src/components/editor/gestureHoldsPreviewReload.test.tsx +432 -15
- package/src/components/editor/groupDropKeepsSelection.test.ts +1 -0
- package/src/components/editor/manualEditsDom.ts +7 -7
- package/src/components/editor/manualEditsTypes.ts +5 -0
- package/src/components/editor/manualOffsetDrag.test.ts +23 -0
- package/src/components/editor/manualOffsetDrag.ts +5 -0
- package/src/components/editor/previewGestureStarts.ts +284 -0
- package/src/components/editor/rotateInlineSave.test.ts +1 -0
- package/src/components/editor/shiftDragAxisLock.test.tsx +1 -0
- package/src/components/editor/useDomEditOverlayGestures.ts +67 -71
- package/src/components/nle/NLEContext.test.ts +26 -0
- package/src/components/nle/NLEContext.tsx +8 -3
- package/src/hooks/draggedGsapPosition.ts +8 -0
- package/src/hooks/editMoment.ts +13 -0
- package/src/hooks/gsapDragCommit.ts +2 -1
- package/src/hooks/gsapDragPositionCommit.ts +19 -7
- package/src/hooks/gsapPositionDetection.ts +5 -3
- package/src/hooks/gsapResizeIntercept.ts +11 -4
- package/src/hooks/gsapRuntimeBridge.ts +31 -11
- package/src/hooks/gsapValueAtPlayhead.test.ts +15 -0
- package/src/hooks/gsapValueAtPlayhead.ts +12 -5
- package/src/hooks/timelineEditingHelpers.test.ts +22 -0
- package/src/hooks/timelineEditingHelpers.ts +18 -2
- package/src/hooks/useConsoleErrorCapture.test.tsx +87 -0
- package/src/hooks/useConsoleErrorCapture.ts +18 -22
- package/src/hooks/useDomSelection.test.ts +21 -2
- package/src/hooks/useEditHistoryActions.test.tsx +20 -0
- package/src/hooks/useEditHistoryActions.ts +2 -0
- package/src/hooks/useGsapAwareEditing.test.tsx +38 -0
- package/src/hooks/useGsapAwareEditing.ts +148 -136
- package/src/hooks/useGsapAwareGroupMove.ts +126 -113
- package/src/hooks/useGsapScriptCommits.ts +5 -4
- package/src/hooks/usePreviewPersistence.history.test.tsx +7 -2
- package/src/hooks/usePreviewPersistence.ts +1 -4
- package/src/hooks/useTimelineDeleteOps.test.tsx +10 -0
- package/src/hooks/useTimelineDeleteOps.ts +9 -10
- package/src/index.ts +1 -0
- package/src/player/hooks/useShadowPreviewReload.ts +6 -6
- package/src/player/hooks/useTimelinePlayer.shadowReload.test.ts +14 -0
- package/src/player/hooks/useTimelinePlayer.ts +8 -5
- package/src/player/lib/thumbnailScheduler.test.ts +20 -1
- package/src/player/lib/thumbnailScheduler.ts +1 -1
- package/src/player/lib/timelineElementHelpers.ts +0 -11
- package/src/player/previewReloading.test.ts +48 -0
- package/src/player/previewReloading.ts +48 -0
- package/src/styles/studio.css +9 -0
- package/src/utils/gsapUndoRestore.browser.test.ts +21 -12
- package/src/utils/rootDuration.ts +5 -4
- package/src/utils/studioPendingEdits.test.ts +27 -0
- package/src/utils/studioPendingEdits.ts +9 -0
- package/src/utils/timelineAssetDrop.test.ts +13 -4
- package/src/utils/timelineAssetDrop.ts +6 -2
- package/dist/chunk-TDWGXBUT.js.map +0 -1
- /package/dist/{chunk-4S3AYCOG.js.map → chunk-E422JDF5.js.map} +0 -0
- /package/dist/{chunk-7UQWVN52.js.map → chunk-UYWON5AX.js.map} +0 -0
- /package/dist/{domEditingLayers-IEVLO54Z.js.map → domEditingLayers-KBTPQKGA.js.map} +0 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@hyperframes/studio",
|
|
3
|
-
"version": "0.8.
|
|
3
|
+
"version": "0.8.139",
|
|
4
4
|
"description": "",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -60,12 +60,12 @@
|
|
|
60
60
|
"dockview-react": "8.3.1",
|
|
61
61
|
"gsap": "^3.13.0",
|
|
62
62
|
"mediabunny": "^1.45.3",
|
|
63
|
-
"@hyperframes/core": "0.8.
|
|
64
|
-
"@hyperframes/
|
|
65
|
-
"@hyperframes/
|
|
66
|
-
"@hyperframes/
|
|
67
|
-
"@hyperframes/
|
|
68
|
-
"@hyperframes/
|
|
63
|
+
"@hyperframes/core": "0.8.139",
|
|
64
|
+
"@hyperframes/player": "0.8.139",
|
|
65
|
+
"@hyperframes/shader-transitions": "0.8.139",
|
|
66
|
+
"@hyperframes/studio-server": "0.8.139",
|
|
67
|
+
"@hyperframes/sdk": "0.8.139",
|
|
68
|
+
"@hyperframes/parsers": "0.8.139"
|
|
69
69
|
},
|
|
70
70
|
"devDependencies": {
|
|
71
71
|
"@tailwindcss/vite": "^4.3.3",
|
|
@@ -73,6 +73,7 @@
|
|
|
73
73
|
"@types/react-dom": "19",
|
|
74
74
|
"@vitejs/plugin-react": "^4.0.0",
|
|
75
75
|
"chokidar": "^4.0.3",
|
|
76
|
+
"esbuild": "^0.25.12",
|
|
76
77
|
"fake-indexeddb": "^6.2.5",
|
|
77
78
|
"puppeteer-core": "^25.2.1",
|
|
78
79
|
"tailwindcss": "^4.3.3",
|
|
@@ -81,7 +82,7 @@
|
|
|
81
82
|
"vite": "^6.4.2",
|
|
82
83
|
"vitest": "^4.1.11",
|
|
83
84
|
"zustand": "^5.0.0",
|
|
84
|
-
"@hyperframes/producer": "0.8.
|
|
85
|
+
"@hyperframes/producer": "0.8.139"
|
|
85
86
|
},
|
|
86
87
|
"peerDependencies": {
|
|
87
88
|
"react": "19",
|
package/src/App.tsx
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { useOwnPreviewIframe, usePreviewIframeStore } from "./player/store/previewIframeStore";
|
|
2
2
|
import { buildProjectApiPath } from "./utils/projectRouting";
|
|
3
|
-
import { useState, useCallback, useRef, useMemo } from "react";
|
|
3
|
+
import { useState, useCallback, useRef, useMemo, type SetStateAction } from "react";
|
|
4
4
|
import { useStableHandlers } from "./hooks/useStableHandlers";
|
|
5
5
|
import { useHistoryFlags, useToolbarSession } from "./hooks/useShellSlices";
|
|
6
6
|
import { useDismissingTabSetter, useRightPanelIntent } from "./hooks/useRightPanelIntents";
|
|
@@ -62,6 +62,7 @@ import { useStudioSessionStart } from "./hooks/useStudioSessionStart";
|
|
|
62
62
|
import { useTimelineAddAtPlayhead } from "./hooks/useTimelineAddAtPlayhead";
|
|
63
63
|
import { readStudioUrlStateFromWindow, resolveMasterCompositionPath } from "./utils/studioUrlState";
|
|
64
64
|
import { useActiveComposition } from "./hooks/useActiveComposition";
|
|
65
|
+
import { requestPreviewReload } from "./player/previewReloading";
|
|
65
66
|
const getTimelineSelectionSet = () => usePlayerStore.getState().selectedElementIds;
|
|
66
67
|
|
|
67
68
|
export interface StudioAppProps {
|
|
@@ -79,7 +80,7 @@ export function StudioApp({ readOnlyPreview = false, readOnlyPreviewReason }: St
|
|
|
79
80
|
const [compIdToSrc, setCompIdToSrc] = useState<Map<string, string>>(new Map());
|
|
80
81
|
const previewIframe = useOwnPreviewIframe();
|
|
81
82
|
const [compositionLoading, setCompositionLoading] = useState(true);
|
|
82
|
-
const [refreshKey,
|
|
83
|
+
const [refreshKey, setRefreshKeyState] = useState(0);
|
|
83
84
|
const [previewDocumentVersion, refreshPreviewDocumentVersion] = usePreviewDocumentVersion();
|
|
84
85
|
const [blockPreview, setBlockPreview] = useState<BlockPreviewInfo | null>(null);
|
|
85
86
|
const previewIframeRef = useRef<HTMLIFrameElement | null>(null);
|
|
@@ -104,7 +105,11 @@ export function StudioApp({ readOnlyPreview = false, readOnlyPreviewReason }: St
|
|
|
104
105
|
const handleDomZIndexReorderCommitRef = useRef<TimelineZIndexReorderCommit | null>(null);
|
|
105
106
|
const pendingTimelineEditPathRef = useRef(new Set<string>());
|
|
106
107
|
const isGestureRecordingRef = useRef(false);
|
|
107
|
-
const
|
|
108
|
+
const setRefreshKey = useCallback((next: SetStateAction<number>) => {
|
|
109
|
+
requestPreviewReload();
|
|
110
|
+
setRefreshKeyState(next);
|
|
111
|
+
}, []);
|
|
112
|
+
const reloadPreview = useCallback(() => setRefreshKey((k) => k + 1), [setRefreshKey]);
|
|
108
113
|
const fileManagerResult = useFileManager({
|
|
109
114
|
projectId,
|
|
110
115
|
showToast,
|
|
@@ -144,7 +149,7 @@ export function StudioApp({ readOnlyPreview = false, readOnlyPreviewReason }: St
|
|
|
144
149
|
recordEdit: editHistory.recordEdit,
|
|
145
150
|
previewIframeRef,
|
|
146
151
|
activeCompPathRef,
|
|
147
|
-
reloadPreview
|
|
152
|
+
reloadPreview,
|
|
148
153
|
});
|
|
149
154
|
const previewPersistence = useStableHandlers(previewPersistenceResult, projectId);
|
|
150
155
|
const externalFileChanges = useStudioExternalFileChanges({
|
|
@@ -357,11 +362,7 @@ export function StudioApp({ readOnlyPreview = false, readOnlyPreviewReason }: St
|
|
|
357
362
|
waitForPendingDomEditSaves: previewPersistence.waitForPendingDomEditSaves,
|
|
358
363
|
});
|
|
359
364
|
const frameCapture = useStableHandlers(frameCaptureResult, projectId);
|
|
360
|
-
const {
|
|
361
|
-
consoleErrors,
|
|
362
|
-
setConsoleErrors,
|
|
363
|
-
resetErrors: resetConsoleErrors,
|
|
364
|
-
} = useConsoleErrorCapture(previewIframe);
|
|
365
|
+
const { consoleErrors, setConsoleErrors } = useConsoleErrorCapture(previewIframe);
|
|
365
366
|
const fileDrop = useGlobalFileDrop(timelineEditing.handleTimelineFileDrop);
|
|
366
367
|
const handleToggleRecordingRef = useRef<(method?: "button" | "keyboard") => void>(() => {});
|
|
367
368
|
const domEditSessionRef = useRef(domEditSession);
|
|
@@ -385,10 +386,9 @@ export function StudioApp({ readOnlyPreview = false, readOnlyPreviewReason }: St
|
|
|
385
386
|
previewIframeRef.current = iframe;
|
|
386
387
|
usePreviewIframeStore.getState().setIframe(iframe);
|
|
387
388
|
appHotkeys.syncPreviewHotkeys(iframe);
|
|
388
|
-
resetConsoleErrors();
|
|
389
389
|
refreshPreviewDocumentVersion();
|
|
390
390
|
},
|
|
391
|
-
[appHotkeys,
|
|
391
|
+
[appHotkeys, refreshPreviewDocumentVersion],
|
|
392
392
|
);
|
|
393
393
|
const rightPanel = useRightPanelIntent();
|
|
394
394
|
const { inspectorPanelActive, shouldShowMotionPath, shouldShowSelectedDomBounds } =
|
|
@@ -10,6 +10,7 @@ import { useZOrderCrossedFlash, ZOrderCrossedFlash } from "./useZOrderCrossedFla
|
|
|
10
10
|
import { useCanvasContextMenuState } from "./useCanvasContextMenuState";
|
|
11
11
|
import {
|
|
12
12
|
type BlockedMoveState,
|
|
13
|
+
type WaitingPressState,
|
|
13
14
|
type DomEditGroupPathOffsetCommit,
|
|
14
15
|
type FocusableDomEditOverlay,
|
|
15
16
|
type MoveCommitOptions,
|
|
@@ -166,6 +167,7 @@ export const DomEditOverlay = memo(function DomEditOverlay({
|
|
|
166
167
|
const gestureRef = useRef<GestureState | null>(null);
|
|
167
168
|
const groupGestureRef = useRef<GroupGestureState | null>(null);
|
|
168
169
|
const blockedMoveRef = useRef<BlockedMoveState | null>(null);
|
|
170
|
+
const waitingPressRef = useRef<WaitingPressState | null>(null);
|
|
169
171
|
const suppressNextBoxClickRef = useRef(false);
|
|
170
172
|
const snapGuidesRef = useRef<SnapGuidesState | null>(null);
|
|
171
173
|
const rafPausedRef = useRef(false);
|
|
@@ -273,6 +275,7 @@ export const DomEditOverlay = memo(function DomEditOverlay({
|
|
|
273
275
|
});
|
|
274
276
|
|
|
275
277
|
const gestures = createDomEditOverlayGestureHandlers({
|
|
278
|
+
activeCompositionPathRef,
|
|
276
279
|
overlayRef,
|
|
277
280
|
iframeRef,
|
|
278
281
|
boxRef,
|
|
@@ -283,6 +286,7 @@ export const DomEditOverlay = memo(function DomEditOverlay({
|
|
|
283
286
|
gestureRef,
|
|
284
287
|
groupGestureRef,
|
|
285
288
|
blockedMoveRef,
|
|
289
|
+
waitingPressRef,
|
|
286
290
|
rafPausedRef,
|
|
287
291
|
suppressNextBoxClickRef,
|
|
288
292
|
setOverlayRect,
|
|
@@ -299,17 +303,17 @@ export const DomEditOverlay = memo(function DomEditOverlay({
|
|
|
299
303
|
});
|
|
300
304
|
|
|
301
305
|
useEffect(() => {
|
|
302
|
-
if (readOnly) gestures.clearPointerState(selectionRef);
|
|
306
|
+
if (readOnly) gestures.clearPointerState(selectionRef, true);
|
|
303
307
|
}, [gestures, readOnly, selectionRef]);
|
|
304
308
|
// A gesture that loses its pointer, the window or the overlay is cancelled, so its mark goes too.
|
|
305
|
-
const cancelGestureRef = useRef(() => {});
|
|
306
|
-
cancelGestureRef.current = () => gestures.clearPointerState(selectionRef);
|
|
309
|
+
const cancelGestureRef = useRef((_dropQueued?: boolean) => {});
|
|
310
|
+
cancelGestureRef.current = (dropQueued) => gestures.clearPointerState(selectionRef, dropQueued);
|
|
307
311
|
useMountEffect(() => {
|
|
308
312
|
const cancel = () => cancelGestureRef.current();
|
|
309
313
|
window.addEventListener("blur", cancel);
|
|
310
314
|
return () => {
|
|
311
315
|
window.removeEventListener("blur", cancel);
|
|
312
|
-
|
|
316
|
+
cancelGestureRef.current(true);
|
|
313
317
|
};
|
|
314
318
|
});
|
|
315
319
|
|
|
@@ -493,7 +497,7 @@ export const DomEditOverlay = memo(function DomEditOverlay({
|
|
|
493
497
|
onPointerLeave={() => onCanvasPointerLeaveRef.current()}
|
|
494
498
|
onPointerUp={marquee.onPointerUp}
|
|
495
499
|
onPointerCancel={marquee.onPointerCancel}
|
|
496
|
-
onLostPointerCapture={
|
|
500
|
+
onLostPointerCapture={gestures.onLostPointerCapture}
|
|
497
501
|
onContextMenu={hostInput ? undefined : handleContextMenu}
|
|
498
502
|
>
|
|
499
503
|
{!hostInput && hoverSelection && hoverRect && compRect.width > 0 && (
|
|
@@ -306,4 +306,29 @@ describe("LayersPanel preview promotion", () => {
|
|
|
306
306
|
expect(collectedRootIds()).toEqual(["a"]);
|
|
307
307
|
fetchSpy.mockRestore();
|
|
308
308
|
});
|
|
309
|
+
|
|
310
|
+
it("a row press starts no text selection, so dragging a row leaves no letters highlighted", () => {
|
|
311
|
+
const doc = new Window().document;
|
|
312
|
+
doc.body.innerHTML = `<div data-composition-id="a"><div id="back"></div><div id="front"></div></div>`;
|
|
313
|
+
const iframe = document.createElement("iframe");
|
|
314
|
+
Object.defineProperty(iframe, "contentDocument", { value: doc });
|
|
315
|
+
const item = (id: string) =>
|
|
316
|
+
({
|
|
317
|
+
key: id,
|
|
318
|
+
element: doc.getElementById(id),
|
|
319
|
+
label: id,
|
|
320
|
+
depth: 0,
|
|
321
|
+
childCount: 0,
|
|
322
|
+
id,
|
|
323
|
+
}) as unknown as DomEditLayerItem;
|
|
324
|
+
mocks.collect.mockReset().mockReturnValue([item("back"), item("front")]);
|
|
325
|
+
mocks.previewIframeRef.current = iframe;
|
|
326
|
+
usePreviewIframeStore.setState({ iframe });
|
|
327
|
+
act(() => root.render(createElement(LayersPanel)));
|
|
328
|
+
act(() => void iframe.dispatchEvent(new Event("load")));
|
|
329
|
+
|
|
330
|
+
const rows = [...host.querySelectorAll("[data-layer-index]")];
|
|
331
|
+
expect(rows).toHaveLength(2);
|
|
332
|
+
expect(rows.every((row) => row.closest(".select-none"))).toBe(true);
|
|
333
|
+
});
|
|
309
334
|
});
|
|
@@ -433,7 +433,7 @@ export const LayersPanel = memo(function LayersPanel({ host }: { host?: LayersPa
|
|
|
433
433
|
</div>
|
|
434
434
|
<div
|
|
435
435
|
ref={scrollContainerRef}
|
|
436
|
-
className="relative min-h-0 flex-1 overflow-y-auto py-1"
|
|
436
|
+
className="relative min-h-0 flex-1 select-none overflow-y-auto py-1"
|
|
437
437
|
onPointerMove={handleContainerPointerMove}
|
|
438
438
|
onPointerUp={handleContainerPointerUp}
|
|
439
439
|
onPointerCancel={handleContainerPointerUp}
|