@hyperframes/studio 0.7.57 → 0.7.58

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 (112) hide show
  1. package/dist/assets/{hyperframes-player--Z69cEkE.js → hyperframes-player-CtTDO63S.js} +1 -1
  2. package/dist/assets/{index-DfmYkU44.js → index-B_UvTX3E.js} +204 -204
  3. package/dist/assets/{index-KsfE1bUu.js → index-C47jAC3Q.js} +1 -1
  4. package/dist/assets/{index-Bf1x1y8H.js → index-DeQPzqwH.js} +1 -1
  5. package/dist/assets/index-uahwWkgw.css +1 -0
  6. package/dist/{chunk-5QSIMBEJ.js → chunk-OBAG3GWK.js} +33 -21
  7. package/dist/chunk-OBAG3GWK.js.map +1 -0
  8. package/dist/{domEditingLayers-6LQGKPOI.js → domEditingLayers-2CKWGEHS.js} +2 -2
  9. package/dist/index.d.ts +15 -4
  10. package/dist/index.html +2 -2
  11. package/dist/index.js +5954 -4474
  12. package/dist/index.js.map +1 -1
  13. package/package.json +7 -7
  14. package/src/App.tsx +3 -3
  15. package/src/components/StudioFeedbackBar.tsx +2 -2
  16. package/src/components/editor/CanvasContextMenu.test.tsx +27 -14
  17. package/src/components/editor/CanvasContextMenu.tsx +71 -6
  18. package/src/components/editor/DomEditOverlay.tsx +5 -2
  19. package/src/components/editor/LayersPanel.tsx +110 -99
  20. package/src/components/editor/canvasContextMenuZOrder.test.ts +57 -0
  21. package/src/components/editor/canvasContextMenuZOrder.ts +40 -1
  22. package/src/components/editor/domEditingDom.ts +5 -6
  23. package/src/components/editor/domEditingElement.ts +15 -32
  24. package/src/components/editor/layersPanelSort.ts +80 -0
  25. package/src/components/editor/useLayerRevealOverride.test.ts +169 -0
  26. package/src/components/editor/useLayerRevealOverride.ts +389 -0
  27. package/src/components/nle/PreviewOverlays.tsx +27 -2
  28. package/src/components/nle/TimelinePane.test.ts +3 -0
  29. package/src/components/nle/TimelinePane.tsx +11 -1
  30. package/src/components/nle/useCanvasZOrderTimelineMirror.test.tsx +440 -0
  31. package/src/components/nle/useCanvasZOrderTimelineMirror.ts +191 -0
  32. package/src/components/nle/useTimelineEditCallbacks.ts +1 -0
  33. package/src/components/nle/zLaneGesture.test.ts +176 -0
  34. package/src/components/nle/zLaneGesture.ts +77 -0
  35. package/src/hooks/domEditCommitTypes.ts +17 -1
  36. package/src/hooks/elementLifecycleOpsTestUtils.ts +25 -0
  37. package/src/hooks/fetchStubTestUtils.ts +16 -0
  38. package/src/hooks/timelineEditingHelpers.test.ts +92 -1
  39. package/src/hooks/timelineEditingHelpers.ts +32 -15
  40. package/src/hooks/timelineMoveAdapter.ts +2 -1
  41. package/src/hooks/timelineTimingSync.test.ts +703 -33
  42. package/src/hooks/timelineTimingSync.ts +282 -97
  43. package/src/hooks/timelineTrackVisibility.test.ts +3 -1
  44. package/src/hooks/timelineTrackVisibility.ts +4 -3
  45. package/src/hooks/useClipboard.ts +19 -17
  46. package/src/hooks/useDomEditCommits.test.tsx +316 -38
  47. package/src/hooks/useDomEditCommits.ts +143 -78
  48. package/src/hooks/useDomEditSession.test.tsx +3 -1
  49. package/src/hooks/useDomEditSession.ts +1 -1
  50. package/src/hooks/useElementLifecycleOps.test.tsx +426 -60
  51. package/src/hooks/useElementLifecycleOps.ts +174 -81
  52. package/src/hooks/usePreviewPersistence.ts +2 -2
  53. package/src/hooks/useTimelineEditing.test.tsx +302 -154
  54. package/src/hooks/useTimelineEditing.ts +97 -93
  55. package/src/hooks/useTimelineEditingTypes.ts +1 -1
  56. package/src/hooks/useTimelineGroupEditing.ts +35 -3
  57. package/src/player/components/Timeline.test.ts +31 -21
  58. package/src/player/components/Timeline.tsx +62 -91
  59. package/src/player/components/TimelineCanvas.tsx +36 -5
  60. package/src/player/components/TimelineLanes.tsx +32 -10
  61. package/src/player/components/TimelineOverlays.tsx +36 -0
  62. package/src/player/components/TimelineRuler.tsx +18 -5
  63. package/src/player/components/TrackGapContextMenu.tsx +116 -0
  64. package/src/player/components/timelineCallbacks.ts +4 -1
  65. package/src/player/components/timelineClipDragCommit.test.ts +279 -3
  66. package/src/player/components/timelineClipDragCommit.ts +173 -71
  67. package/src/player/components/timelineGapCommit.test.ts +163 -0
  68. package/src/player/components/timelineGapCommit.ts +103 -0
  69. package/src/player/components/timelineGaps.test.ts +221 -0
  70. package/src/player/components/timelineGaps.ts +182 -0
  71. package/src/player/components/timelineLayout.test.ts +2 -1
  72. package/src/player/components/timelineLayout.ts +22 -6
  73. package/src/player/components/timelineMarquee.test.ts +20 -10
  74. package/src/player/components/timelineMarquee.ts +9 -2
  75. package/src/player/components/timelineStackingSync.test.ts +42 -1
  76. package/src/player/components/timelineStackingSync.ts +31 -16
  77. package/src/player/components/timelineZMirror.test.ts +667 -0
  78. package/src/player/components/timelineZMirror.ts +393 -0
  79. package/src/player/components/timelineZoom.test.ts +2 -2
  80. package/src/player/components/timelineZoom.ts +7 -3
  81. package/src/player/components/useTimelineClipDrag.ts +1 -1
  82. package/src/player/components/useTimelineGapHighlights.test.ts +119 -0
  83. package/src/player/components/useTimelineGapHighlights.ts +110 -0
  84. package/src/player/components/useTimelinePlayhead.ts +4 -3
  85. package/src/player/components/useTimelineRangeSelection.ts +6 -4
  86. package/src/player/components/useTimelineScrollViewport.ts +73 -0
  87. package/src/player/components/useTimelineStackingSync.test.tsx +0 -1
  88. package/src/player/components/useTimelineStackingSync.ts +5 -3
  89. package/src/player/components/useTimelineTrackDerivations.ts +38 -0
  90. package/src/player/components/useTrackGapMenu.ts +155 -0
  91. package/src/player/hooks/useExpandedTimelineElements.test.ts +67 -4
  92. package/src/player/hooks/useExpandedTimelineElements.ts +12 -1
  93. package/src/player/hooks/useTimelineSyncCallbacks.ts +2 -0
  94. package/src/player/lib/layerOrdering.test.ts +1 -15
  95. package/src/player/lib/layerOrdering.ts +5 -28
  96. package/src/player/lib/timelineDOM.test.ts +72 -0
  97. package/src/player/lib/timelineDOM.ts +3 -0
  98. package/src/player/lib/timelineElementHelpers.ts +35 -11
  99. package/src/player/store/playerStore.ts +12 -1
  100. package/src/telemetry/events.test.ts +10 -0
  101. package/src/telemetry/events.ts +1 -0
  102. package/src/utils/domEditSaveQueue.ts +4 -3
  103. package/src/utils/editHistory.test.ts +82 -0
  104. package/src/utils/editHistory.ts +14 -2
  105. package/src/utils/gsapSoftReload.test.ts +54 -115
  106. package/src/utils/gsapSoftReload.ts +42 -152
  107. package/src/utils/gsapUndoRestore.test.ts +269 -0
  108. package/src/utils/gsapUndoRestore.ts +269 -0
  109. package/src/utils/sourceScopedSelectorIndex.ts +29 -0
  110. package/dist/assets/index-_pqzyxB1.css +0 -1
  111. package/dist/chunk-5QSIMBEJ.js.map +0 -1
  112. /package/dist/{domEditingLayers-6LQGKPOI.js.map → domEditingLayers-2CKWGEHS.js.map} +0 -0
@@ -43,6 +43,8 @@ export interface StackingElement {
43
43
  zIndex: number;
44
44
  /** Audio clips have no visual stacking and are excluded from the computation. */
45
45
  isAudio: boolean;
46
+ /** Source document. Leaf z-indexes are comparable only inside this file. */
47
+ sourceFile?: string;
46
48
  /**
47
49
  * CSS stacking context the clip's node lives in (TimelineElement.stackingContextId).
48
50
  * Leaf z-indexes are only comparable WITHIN one context — across contexts the
@@ -70,12 +72,20 @@ export interface StackingPatch {
70
72
  const EPS = 1e-6;
71
73
 
72
74
  /**
73
- * Canonical stacking-context key: null/undefined both mean the root context.
74
- * The ONLY place the normalization lives context partitioning, membership
75
- * checks, and pairwise equality must all go through it.
75
+ * Canonical paint-scope key: leaf z-indexes are comparable only within the same
76
+ * source document and CSS stacking context. The ONLY place this normalization
77
+ * lives — partitioning, membership checks, and pairwise equality all use it.
76
78
  */
77
- const contextKey = (el: { stackingContextId?: string | null }): string | null =>
78
- el.stackingContextId ?? null;
79
+ const paintScopeKey = (el: { sourceFile?: string; stackingContextId?: string | null }): string =>
80
+ JSON.stringify([el.sourceFile ?? null, el.stackingContextId ?? null]);
81
+
82
+ /** Canonical paint-scope equality for stacking sync and its inverse mirror. */
83
+ export function samePaintScope(
84
+ a: { sourceFile?: string; stackingContextId?: string | null },
85
+ b: { sourceFile?: string; stackingContextId?: string | null },
86
+ ): boolean {
87
+ return paintScopeKey(a) === paintScopeKey(b);
88
+ }
79
89
 
80
90
  /**
81
91
  * Two clips overlap in time when their half-open [start, end) intervals intersect.
@@ -86,7 +96,10 @@ const contextKey = (el: { stackingContextId?: string | null }): string | null =>
86
96
  * epsilon guards against float fuzz (e.g. 5.0000001 vs 5) spuriously overlapping two
87
97
  * abutting clips and shuffling lanes. The two are intended to differ, not align.
88
98
  */
89
- function overlapsInTime(a: StackingElement, b: StackingElement): boolean {
99
+ function overlapsInTime(
100
+ a: Pick<StackingElement, "start" | "duration">,
101
+ b: Pick<StackingElement, "start" | "duration">,
102
+ ): boolean {
90
103
  return a.start < b.start + b.duration - EPS && b.start < a.start + a.duration - EPS;
91
104
  }
92
105
 
@@ -114,9 +127,13 @@ interface MutZ extends StackingElement {
114
127
  * Does `a` currently paint ON TOP of `b`? Higher z wins; equal z breaks by DOM
115
128
  * order (later in DOM paints on top). When either domIndex is absent, equal z is
116
129
  * treated as "not strictly above" (ambiguous) — callers should supply domIndex to
117
- * disambiguate (see StackingElement.domIndex). Operates on resolved (`MutZ`) clips.
130
+ * disambiguate (see StackingElement.domIndex). Exported (like laneIsAbove) as the
131
+ * ONE paint-order predicate so every consumer agrees on what "paints above" means.
118
132
  */
119
- function paintsAbove(a: MutZ, b: MutZ): boolean {
133
+ function paintsAbove(
134
+ a: Pick<StackingElement, "zIndex" | "domIndex">,
135
+ b: Pick<StackingElement, "zIndex" | "domIndex">,
136
+ ): boolean {
120
137
  if (a.zIndex !== b.zIndex) return a.zIndex > b.zIndex;
121
138
  if (a.domIndex != null && b.domIndex != null) return a.domIndex > b.domIndex;
122
139
  return false;
@@ -301,12 +318,11 @@ export function computeStackingPatches(
301
318
  // excluded outright (item 13).
302
319
  const allResolved = elements.filter((e) => Number.isFinite(e.zIndex));
303
320
 
304
- // Leaf z is only meaningful within ONE stacking context: across contexts the
305
- // ancestor contexts' z decides paint order, so comparing (or patching) leaf
306
- // values across contexts is nonsense. Restrict the computation to the edited
307
- // clips' own context(s); cross-context lane relations are out of scope.
308
- const editedContexts = new Set(allResolved.filter((e) => editedSet.has(e.key)).map(contextKey));
309
- const resolved = allResolved.filter((e) => editedContexts.has(contextKey(e)));
321
+ // Leaf z is only meaningful within ONE source document and stacking context:
322
+ // across either boundary the ancestor composition/context decides paint order.
323
+ // Restrict the computation to the edited clips' own paint scope(s).
324
+ const editedScopes = new Set(allResolved.filter((e) => editedSet.has(e.key)).map(paintScopeKey));
325
+ const resolved = allResolved.filter((e) => editedScopes.has(paintScopeKey(e)));
310
326
 
311
327
  // Mutable z snapshot so edits + cascaded bumps see each other's applied z.
312
328
  const byKey = new Map<string, MutZ>(resolved.map((e) => [e.key, { ...e }]));
@@ -326,10 +342,9 @@ export function computeStackingPatches(
326
342
  // The full live set, so the transitive cascade can reach clips that overlap a
327
343
  // LIFTED neighbour without overlapping the edited clip itself (#2198).
328
344
  const all = [...byKey.values()];
329
- const sameContext = (a: MutZ, b: MutZ) => contextKey(a) === contextKey(b);
330
345
  const overlappersOf = (clip: MutZ): MutZ[] =>
331
346
  all.filter(
332
- (o) => o.key !== clip.key && !o.isAudio && sameContext(clip, o) && overlapsInTime(clip, o),
347
+ (o) => o.key !== clip.key && !o.isAudio && samePaintScope(clip, o) && overlapsInTime(clip, o),
333
348
  );
334
349
 
335
350
  for (const clip of edited) {