@hyperframes/studio 0.8.124 → 0.8.125

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 (31) hide show
  1. package/dist/assets/{hyperframes-player-ColOZ_78.js → hyperframes-player-CmIh-wq9.js} +1 -1
  2. package/dist/assets/{index-jQEqFKMk.js → index-4LRR6o2F.js} +1 -1
  3. package/dist/assets/{index-BuSTrK-Z.js → index-CrYoEZ5p.js} +139 -139
  4. package/dist/assets/{index-CVuUfURE.js → index-yCK8osBg.js} +1 -1
  5. package/dist/index.d.ts +43 -35
  6. package/dist/index.html +1 -1
  7. package/dist/index.js +213 -94
  8. package/dist/index.js.map +1 -1
  9. package/package.json +8 -8
  10. package/src/components/editor/domEditOverlayGestures.ts +2 -0
  11. package/src/components/editor/domEditOverlayStartGesture.ts +6 -0
  12. package/src/components/editor/dragUndoPaint.test.ts +170 -2
  13. package/src/components/editor/gestureUndoRevert.ts +104 -0
  14. package/src/components/editor/manualOffsetDrag.ts +1 -12
  15. package/src/components/editor/useDomEditNudge.ts +1 -1
  16. package/src/components/editor/useDomEditOverlayGestures.ts +9 -5
  17. package/src/hooks/gestureTransaction.test.ts +60 -0
  18. package/src/hooks/gestureTransaction.ts +5 -2
  19. package/src/hooks/gsapGestureOutcome.ts +9 -2
  20. package/src/hooks/gsapResizeDropPoint.test.ts +39 -1
  21. package/src/hooks/gsapResizeElementSize.test.tsx +27 -0
  22. package/src/hooks/gsapResizeIntercept.ts +55 -68
  23. package/src/hooks/gsapScriptCommitTypes.ts +2 -0
  24. package/src/hooks/useGsapAwareEditing.groupPlan.test.tsx +29 -1
  25. package/src/hooks/useGsapAwareEditing.test.tsx +1 -0
  26. package/src/hooks/useGsapAwareEditing.ts +21 -25
  27. package/src/hooks/useGsapAwareGroupMove.ts +4 -6
  28. package/src/hooks/useGsapScriptCommits.test.tsx +42 -1
  29. package/src/hooks/useGsapScriptCommits.ts +12 -3
  30. package/src/utils/studioPendingEdits.test.ts +52 -0
  31. package/src/utils/studioPendingEdits.ts +55 -10
@@ -14,11 +14,25 @@ export type StudioEditRevert = () => () => void;
14
14
  interface PendingEdit {
15
15
  revert: StudioEditRevert | null;
16
16
  landed: () => Promise<boolean>;
17
+ redraws: Array<() => void>;
18
+ showAgain: (() => void) | null;
19
+ }
20
+
21
+ export interface StudioEditInFlight {
22
+ reverted: () => boolean;
23
+ within: <T>(run: () => T) => T;
24
+ drawUnlessUndone: (draw: () => void) => void;
25
+ drawKeepingUndone: <T>(draw: () => T) => T;
26
+ markSaved: () => void;
17
27
  }
18
28
 
19
29
  const pendingEdits = new Map<Promise<unknown>, PendingEdit>();
20
30
  const NOT_SAVED = () => Promise.resolve(false);
21
- let adopting = false;
31
+ let adopting: StudioEditInFlight | null = null;
32
+
33
+ export function adoptingStudioPendingEdit(): StudioEditInFlight | null {
34
+ return adopting;
35
+ }
22
36
 
23
37
  function waitForPostBlurEffects(): Promise<void> {
24
38
  return new Promise((resolve) => setTimeout(resolve, 0));
@@ -73,7 +87,7 @@ export function trackStudioPendingEdit(
73
87
  if (!result) return undefined;
74
88
  const promise = Promise.resolve(result);
75
89
  if (adopting) return promise;
76
- pendingEdits.set(promise, { revert: null, landed: NOT_SAVED });
90
+ pendingEdits.set(promise, { revert: null, landed: NOT_SAVED, redraws: [], showAgain: null });
77
91
  promise.then(
78
92
  () => pendingEdits.delete(promise),
79
93
  () => pendingEdits.delete(promise),
@@ -97,25 +111,49 @@ export function beginStudioPendingEdit(revert: StudioEditRevert | null) {
97
111
  const entry = pendingEdits.get(promise)!;
98
112
  entry.revert = revert;
99
113
  let landed = Promise.resolve(false);
114
+ let saved = false;
100
115
  entry.landed = () => landed;
116
+ const inFlight: StudioEditInFlight = {
117
+ reverted: () => entry.revert === null && revert !== null,
118
+ within(run) {
119
+ const outer = adopting;
120
+ adopting = inFlight;
121
+ try {
122
+ return run();
123
+ } finally {
124
+ adopting = outer;
125
+ }
126
+ },
127
+ drawUnlessUndone(draw) {
128
+ if (inFlight.reverted()) entry.redraws.push(draw);
129
+ else draw();
130
+ },
131
+ drawKeepingUndone(draw) {
132
+ if (!inFlight.reverted()) return draw();
133
+ entry.showAgain?.();
134
+ try {
135
+ return draw();
136
+ } finally {
137
+ entry.showAgain = revert!();
138
+ }
139
+ },
140
+ markSaved: () => void (saved = true),
141
+ };
101
142
  return {
102
143
  settle,
103
- reverted: () => entry.revert === null && revert !== null,
104
- // Only what `start` registers synchronously is adopted; a registration after an await is a newer edit.
144
+ reverted: inFlight.reverted,
145
+ // Only what `start` registers synchronously is adopted; a later write joins only through `within`.
105
146
  adopt<T>(start: () => T): T {
106
- adopting = true;
107
147
  try {
108
- const committed = start();
148
+ const committed = inFlight.within(start);
109
149
  landed = Promise.resolve(committed).then(
110
150
  () => true,
111
- () => false,
151
+ () => saved,
112
152
  );
113
153
  return committed;
114
154
  } catch (error) {
115
155
  settle();
116
156
  throw error;
117
- } finally {
118
- adopting = false;
119
157
  }
120
158
  },
121
159
  };
@@ -129,7 +167,14 @@ export function paintBackNewestStudioPendingEdit(): {
129
167
  const revert = newest?.revert;
130
168
  if (!newest || !revert) return null;
131
169
  newest.revert = null;
132
- return { showAgain: revert(), landed: newest.landed };
170
+ newest.showAgain = revert();
171
+ return {
172
+ showAgain: () => {
173
+ newest.showAgain?.();
174
+ for (const redraw of newest.redraws.splice(0)) redraw();
175
+ },
176
+ landed: newest.landed,
177
+ };
133
178
  }
134
179
 
135
180
  export function revertNewestStudioPendingEdit(): (() => void) | null {