@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.
Files changed (85) hide show
  1. package/dist/assets/{hyperframes-player-D_Mh6hbx.js → hyperframes-player-CckOoCJ8.js} +1 -1
  2. package/dist/assets/{index-CHEctGzc.js → index-BmIPrb8I.js} +1 -1
  3. package/dist/assets/{index-B3lJsA-e.js → index-Br1Whc0f.js} +189 -189
  4. package/dist/assets/{index-CC_E-Cbl.css → index-CVd4O6eH.css} +1 -1
  5. package/dist/assets/{index-rtccfg9b.js → index-DsEkE5_G.js} +1 -1
  6. package/dist/{chunk-4S3AYCOG.js → chunk-E422JDF5.js} +2 -2
  7. package/dist/{chunk-TDWGXBUT.js → chunk-TFLU2MGI.js} +1 -6
  8. package/dist/chunk-TFLU2MGI.js.map +1 -0
  9. package/dist/{chunk-7UQWVN52.js → chunk-UYWON5AX.js} +2 -2
  10. package/dist/{domEditingLayers-IEVLO54Z.js → domEditingLayers-KBTPQKGA.js} +3 -3
  11. package/dist/index.d.ts +2 -1
  12. package/dist/index.html +2 -2
  13. package/dist/index.js +867 -499
  14. package/dist/index.js.map +1 -1
  15. package/dist/player.js +2 -2
  16. package/dist/styles.css +1 -1
  17. package/package.json +9 -8
  18. package/src/App.tsx +11 -11
  19. package/src/components/editor/DomEditOverlay.tsx +9 -5
  20. package/src/components/editor/LayersPanel.test.ts +25 -0
  21. package/src/components/editor/LayersPanel.tsx +1 -1
  22. package/src/components/editor/PropertyPanel.test.tsx +600 -748
  23. package/src/components/editor/anchoredResizeCommitFeedsOffset.test.ts +2 -0
  24. package/src/components/editor/domEditOverlayGeometry.ts +7 -7
  25. package/src/components/editor/domEditOverlayGestures.ts +18 -0
  26. package/src/components/editor/domEditOverlayStartGesture.blocked.test.ts +1 -0
  27. package/src/components/editor/domEditOverlayStartGesture.test.ts +3 -0
  28. package/src/components/editor/domEditOverlayStartGesture.ts +9 -1
  29. package/src/components/editor/dragUndoPaint.test.ts +2 -0
  30. package/src/components/editor/gestureHoldsPreviewReload.test.tsx +432 -15
  31. package/src/components/editor/groupDropKeepsSelection.test.ts +1 -0
  32. package/src/components/editor/manualEditsDom.ts +7 -7
  33. package/src/components/editor/manualEditsTypes.ts +5 -0
  34. package/src/components/editor/manualOffsetDrag.test.ts +23 -0
  35. package/src/components/editor/manualOffsetDrag.ts +5 -0
  36. package/src/components/editor/previewGestureStarts.ts +284 -0
  37. package/src/components/editor/rotateInlineSave.test.ts +1 -0
  38. package/src/components/editor/shiftDragAxisLock.test.tsx +1 -0
  39. package/src/components/editor/useDomEditOverlayGestures.ts +67 -71
  40. package/src/components/nle/NLEContext.test.ts +26 -0
  41. package/src/components/nle/NLEContext.tsx +8 -3
  42. package/src/hooks/draggedGsapPosition.ts +8 -0
  43. package/src/hooks/editMoment.ts +13 -0
  44. package/src/hooks/gsapDragCommit.ts +2 -1
  45. package/src/hooks/gsapDragPositionCommit.ts +19 -7
  46. package/src/hooks/gsapPositionDetection.ts +5 -3
  47. package/src/hooks/gsapResizeIntercept.ts +11 -4
  48. package/src/hooks/gsapRuntimeBridge.ts +31 -11
  49. package/src/hooks/gsapValueAtPlayhead.test.ts +15 -0
  50. package/src/hooks/gsapValueAtPlayhead.ts +12 -5
  51. package/src/hooks/timelineEditingHelpers.test.ts +22 -0
  52. package/src/hooks/timelineEditingHelpers.ts +18 -2
  53. package/src/hooks/useConsoleErrorCapture.test.tsx +87 -0
  54. package/src/hooks/useConsoleErrorCapture.ts +18 -22
  55. package/src/hooks/useDomSelection.test.ts +21 -2
  56. package/src/hooks/useEditHistoryActions.test.tsx +20 -0
  57. package/src/hooks/useEditHistoryActions.ts +2 -0
  58. package/src/hooks/useGsapAwareEditing.test.tsx +38 -0
  59. package/src/hooks/useGsapAwareEditing.ts +148 -136
  60. package/src/hooks/useGsapAwareGroupMove.ts +126 -113
  61. package/src/hooks/useGsapScriptCommits.ts +5 -4
  62. package/src/hooks/usePreviewPersistence.history.test.tsx +7 -2
  63. package/src/hooks/usePreviewPersistence.ts +1 -4
  64. package/src/hooks/useTimelineDeleteOps.test.tsx +10 -0
  65. package/src/hooks/useTimelineDeleteOps.ts +9 -10
  66. package/src/index.ts +1 -0
  67. package/src/player/hooks/useShadowPreviewReload.ts +6 -6
  68. package/src/player/hooks/useTimelinePlayer.shadowReload.test.ts +14 -0
  69. package/src/player/hooks/useTimelinePlayer.ts +8 -5
  70. package/src/player/lib/thumbnailScheduler.test.ts +20 -1
  71. package/src/player/lib/thumbnailScheduler.ts +1 -1
  72. package/src/player/lib/timelineElementHelpers.ts +0 -11
  73. package/src/player/previewReloading.test.ts +48 -0
  74. package/src/player/previewReloading.ts +48 -0
  75. package/src/styles/studio.css +9 -0
  76. package/src/utils/gsapUndoRestore.browser.test.ts +21 -12
  77. package/src/utils/rootDuration.ts +5 -4
  78. package/src/utils/studioPendingEdits.test.ts +27 -0
  79. package/src/utils/studioPendingEdits.ts +9 -0
  80. package/src/utils/timelineAssetDrop.test.ts +13 -4
  81. package/src/utils/timelineAssetDrop.ts +6 -2
  82. package/dist/chunk-TDWGXBUT.js.map +0 -1
  83. /package/dist/{chunk-4S3AYCOG.js.map → chunk-E422JDF5.js.map} +0 -0
  84. /package/dist/{chunk-7UQWVN52.js.map → chunk-UYWON5AX.js.map} +0 -0
  85. /package/dist/{domEditingLayers-IEVLO54Z.js.map → domEditingLayers-KBTPQKGA.js.map} +0 -0
@@ -142,6 +142,7 @@ function buildHarness(
142
142
  const iframe = document.createElement("iframe");
143
143
 
144
144
  const opts: UseDomEditOverlayGesturesOptions = {
145
+ activeCompositionPathRef: { current: null },
145
146
  overlayRef: ref<HTMLDivElement | null>(overlayEl),
146
147
  iframeRef: ref<HTMLIFrameElement | null>(iframe),
147
148
  boxRef: ref<HTMLDivElement | null>(document.createElement("div")),
@@ -159,6 +160,7 @@ function buildHarness(
159
160
  gestureRef: ref<GestureState | null>(null),
160
161
  groupGestureRef: ref(null),
161
162
  blockedMoveRef: ref(null),
163
+ waitingPressRef: ref(null),
162
164
  rafPausedRef: ref(false),
163
165
  suppressNextBoxClickRef: ref(false),
164
166
  setOverlayRect: () => {},
@@ -18,16 +18,16 @@ export interface OverlayRect {
18
18
  height: number;
19
19
  editScaleX: number;
20
20
  editScaleY: number;
21
- /**
22
- * The element's live transform rotation in DEGREES (screen/CSS convention, CW
23
- * positive), decomposed from its computed transform matrix. Present so the
24
- * selection chrome can render as an oriented bounding box (OBB) that co-rotates
25
- * with the element. Omitted (treated as 0) for group/union rects and when the
26
- * transform is unmeasurable — those render axis-aligned exactly as before.
27
- */
21
+ /** Live screen-space rotation; omitted for axis-aligned group bounds. */
28
22
  angle?: number;
29
23
  }
30
24
 
25
+ export const shiftedOverlayRect = (rect: OverlayRect, dx: number, dy: number): OverlayRect => ({
26
+ ...rect,
27
+ left: rect.left + dx,
28
+ top: rect.top + dy,
29
+ });
30
+
31
31
  export interface GroupOverlayItem {
32
32
  key: string;
33
33
  selection: DomEditSelection;
@@ -121,6 +121,22 @@ export interface BlockedMoveState {
121
121
  startY: number;
122
122
  }
123
123
 
124
+ /** Marks the selection box while its press waits for a reload: it is drawn at the pointer, not at the element. */
125
+ export const PRESS_WAITING_ATTR = "data-dom-edit-press-waiting";
126
+
127
+ /** A press that landed while the preview reloads: it starts once the new preview shows what it pressed. */
128
+ export interface WaitingPressState {
129
+ pointerId: number;
130
+ startX: number;
131
+ startY: number;
132
+ draw: ((dx: number, dy: number) => void) | null;
133
+ frame: number;
134
+ moved: React.PointerEvent<HTMLDivElement> | null;
135
+ released: React.PointerEvent<HTMLDivElement> | null;
136
+ after: WaitingPressState | null;
137
+ ended: boolean;
138
+ }
139
+
124
140
  export type FocusableDomEditOverlay = {
125
141
  focus(options?: FocusOptions): void;
126
142
  };
@@ -245,6 +261,7 @@ export interface DomEditGroupPathOffsetCommit {
245
261
 
246
262
  // Refs are stable across renders; values are read via .current.
247
263
  export type UseDomEditOverlayGesturesOptions = {
264
+ activeCompositionPathRef: RefObject<string | null>;
248
265
  overlayRef: RefObject<HTMLDivElement | null>;
249
266
  iframeRef: RefObject<HTMLIFrameElement | null>;
250
267
  boxRef: RefObject<HTMLDivElement | null>;
@@ -255,6 +272,7 @@ export type UseDomEditOverlayGesturesOptions = {
255
272
  gestureRef: RefObject<GestureState | null>;
256
273
  groupGestureRef: RefObject<GroupGestureState | null>;
257
274
  blockedMoveRef: RefObject<BlockedMoveState | null>;
275
+ waitingPressRef: RefObject<WaitingPressState | null>;
258
276
  rafPausedRef: RefObject<boolean>;
259
277
  suppressNextBoxClickRef: RefObject<boolean>;
260
278
  setOverlayRect: (next: OverlayRect | null) => void;
@@ -30,6 +30,7 @@ it("a drag press the layer cannot take gets the notice, counts as handled, and l
30
30
  snapGuidesRef: ref(null),
31
31
  groupGestureRef: ref(null),
32
32
  blockedMoveRef: ref(null),
33
+ waitingPressRef: ref(null),
33
34
  setOverlayRect: vi.fn(),
34
35
  suppressNextBoxClickRef: ref(false),
35
36
  hoverSelectionRef: ref(null),
@@ -47,6 +47,7 @@ function pressOptions(element: HTMLElement) {
47
47
  snapGuidesRef: ref(null),
48
48
  groupGestureRef: ref(null),
49
49
  blockedMoveRef: ref(null),
50
+ waitingPressRef: ref(null),
50
51
  setOverlayRect: vi.fn(),
51
52
  suppressNextBoxClickRef: ref(false),
52
53
  hoverSelectionRef: ref(null),
@@ -169,6 +170,7 @@ describe("a rotate on a page that loads GSAP", () => {
169
170
  gestureRef: ref<GestureState | null>(null),
170
171
  groupGestureRef: ref(null),
171
172
  blockedMoveRef: ref(null),
173
+ waitingPressRef: ref(null),
172
174
  rafPausedRef: ref(false),
173
175
  onCanvasPointerMoveRef: ref(vi.fn()),
174
176
  };
@@ -222,6 +224,7 @@ describe("a rotate press on an element a GSAP tween turns", () => {
222
224
  iframeRef: ref(null),
223
225
  gestureRef: ref<GestureState | null>(null),
224
226
  rafPausedRef: ref(false),
227
+ waitingPressRef: ref(null),
225
228
  };
226
229
  const press = {
227
230
  clientX: 25,
@@ -3,6 +3,7 @@
3
3
  * These are pure "start a new gesture" operations — no draft rect updates.
4
4
  */
5
5
  import { type DomEditSelection } from "./domEditing";
6
+ import type { EditMoment } from "./manualEditsTypes";
6
7
  import {
7
8
  applyManualOffsetDragDraft,
8
9
  createManualOffsetDragMember,
@@ -49,6 +50,7 @@ export function notifyBlockedPress(
49
50
  export function startGroupDrag(
50
51
  e: React.PointerEvent<HTMLElement>,
51
52
  opts: UseDomEditOverlayGesturesOptions,
53
+ at?: EditMoment,
52
54
  ): boolean {
53
55
  const items = opts.groupOverlayItemsRef.current;
54
56
  if (items.length <= 1) return false;
@@ -73,6 +75,7 @@ export function startGroupDrag(
73
75
  element: item.element,
74
76
  rect: item.rect,
75
77
  gesture: "drag",
78
+ at,
76
79
  });
77
80
  if (!result.ok) {
78
81
  restoreManualOffsetDragMembers(members);
@@ -144,8 +147,10 @@ export function startGesture(
144
147
  selection?: DomEditSelection;
145
148
  rect?: OverlayRect | null;
146
149
  resizeHandle?: ResizeHandle;
150
+ at?: EditMoment;
147
151
  },
148
152
  ): boolean {
153
+ const at = options?.at;
149
154
  const sel = options?.selection ?? opts.selectionRef.current;
150
155
  const rect = options?.rect ?? opts.overlayRectRef.current;
151
156
  const box = opts.boxRef.current;
@@ -196,6 +201,7 @@ export function startGesture(
196
201
  element: sel.element,
197
202
  rect,
198
203
  gesture: "drag",
204
+ at,
199
205
  });
200
206
  if (!result.ok) {
201
207
  opts.onBlockedMoveRef.current(result.selection, result.reason);
@@ -217,6 +223,7 @@ export function startGesture(
217
223
  element: sel.element,
218
224
  rect,
219
225
  gesture: "resize",
226
+ at,
220
227
  });
221
228
  if (result.ok) {
222
229
  pathOffsetMember = result.member;
@@ -225,12 +232,13 @@ export function startGesture(
225
232
  // Hold a % translate as the same px now, so a growing box can't drag it along mid-frame.
226
233
  if (result.member.plainTranslate) applyManualOffsetDragDraft(result.member, 0, 0);
227
234
  } else {
228
- manualEditDragToken = beginStudioManualEditGesture(sel.element, "resize");
235
+ manualEditDragToken = beginStudioManualEditGesture(sel.element, "resize", at);
229
236
  }
230
237
  } else {
231
238
  manualEditDragToken = beginStudioManualEditGesture(
232
239
  sel.element,
233
240
  kind === "rotate" ? "rotate" : "resize",
241
+ at,
234
242
  );
235
243
  }
236
244
  }
@@ -68,6 +68,7 @@ function dragWithSaveRunning(save: Promise<void> | (() => Promise<void>)) {
68
68
  snapGuidesRef: ref(null),
69
69
  groupGestureRef: ref(null),
70
70
  blockedMoveRef: ref(null),
71
+ waitingPressRef: ref(null),
71
72
  setOverlayRect: vi.fn(),
72
73
  suppressNextBoxClickRef: ref(false),
73
74
  hoverSelectionRef: ref(null),
@@ -127,6 +128,7 @@ function gestureWithSaveRunning(kind: "resize" | "rotate", save: Promise<void>)
127
128
  snapGuidesRef: ref(null),
128
129
  groupGestureRef: ref(null),
129
130
  blockedMoveRef: ref(null),
131
+ waitingPressRef: ref(null),
130
132
  setOverlayRect: vi.fn(),
131
133
  suppressNextBoxClickRef: ref(false),
132
134
  hoverSelectionRef: ref(null),