@hyperframes/studio 0.6.47 → 0.6.49
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-BP6jGdt0.js +418 -0
- package/dist/assets/index-B4Cr7MVx.js +138 -0
- package/dist/index.html +1 -1
- package/package.json +4 -4
- package/src/components/editor/DomEditOverlay.test.ts +3 -2
- package/src/components/editor/DomEditOverlay.tsx +4 -7
- package/src/components/editor/LayersPanel.tsx +8 -7
- package/src/components/editor/domEditing.test.ts +58 -43
- package/src/components/editor/domEditingLayers.ts +56 -5
- package/src/components/editor/useDomEditOverlayGestures.ts +1 -1
- package/src/components/nle/NLEPreview.test.ts +17 -1
- package/src/components/nle/NLEPreview.tsx +58 -8
- package/src/hooks/useDomEditCommits.ts +10 -1
- package/src/hooks/useDomEditSession.ts +4 -4
- package/src/hooks/useDomEditTextCommits.ts +3 -3
- package/src/hooks/useDomSelection.ts +28 -16
- package/src/hooks/usePreviewInteraction.ts +7 -6
- package/src/hooks/useStudioUrlState.ts +4 -3
- package/src/player/hooks/useTimelinePlayer.seek.test.ts +95 -143
- package/src/player/hooks/useTimelinePlayer.ts +26 -27
- package/src/player/lib/playbackAdapter.test.ts +165 -2
- package/src/player/lib/playbackAdapter.ts +12 -4
- package/src/player/lib/playbackSeek.ts +21 -0
- package/src/utils/studioUrlState.test.ts +6 -4
- package/dist/assets/hyperframes-player-CWb0VPYD.js +0 -418
- package/dist/assets/index-DpbZouXZ.js +0 -138
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { memo, useCallback, useEffect, useRef, useState, type
|
|
1
|
+
import { memo, useCallback, useEffect, useRef, useState, type RefObject } from "react";
|
|
2
2
|
import { Player } from "../../player";
|
|
3
3
|
import {
|
|
4
4
|
DEFAULT_PREVIEW_ZOOM,
|
|
@@ -14,7 +14,7 @@ import {
|
|
|
14
14
|
import { readStudioUiPreferences, writeStudioUiPreferences } from "../../utils/studioUiPreferences";
|
|
15
15
|
interface NLEPreviewProps {
|
|
16
16
|
projectId: string;
|
|
17
|
-
iframeRef:
|
|
17
|
+
iframeRef: RefObject<HTMLIFrameElement | null>;
|
|
18
18
|
onIframeLoad: () => void;
|
|
19
19
|
onCompositionLoadingChange?: (loading: boolean) => void;
|
|
20
20
|
portrait?: boolean;
|
|
@@ -37,6 +37,11 @@ const ZOOM_HUD_TIMEOUT_MS = 1200;
|
|
|
37
37
|
const ZOOM_SETTLE_MS = 200;
|
|
38
38
|
const PREVIEW_STAGE_INSET_PX = 16;
|
|
39
39
|
|
|
40
|
+
interface PreviewCompositionSize {
|
|
41
|
+
width: number;
|
|
42
|
+
height: number;
|
|
43
|
+
}
|
|
44
|
+
|
|
40
45
|
function isPreviewAtFit(state: PreviewZoomState): boolean {
|
|
41
46
|
return (
|
|
42
47
|
Math.abs(state.zoomPercent - 100) < 0.5 &&
|
|
@@ -56,14 +61,41 @@ function loadInitialZoom(): PreviewZoomState {
|
|
|
56
61
|
: DEFAULT_PREVIEW_ZOOM;
|
|
57
62
|
}
|
|
58
63
|
|
|
59
|
-
|
|
64
|
+
// fallow-ignore-next-line complexity
|
|
65
|
+
function readPreviewCompositionSize(
|
|
66
|
+
iframe: HTMLIFrameElement | null,
|
|
67
|
+
): PreviewCompositionSize | null {
|
|
68
|
+
try {
|
|
69
|
+
const doc = iframe?.contentDocument;
|
|
70
|
+
const root =
|
|
71
|
+
doc?.querySelector("[data-composition-id][data-width][data-height]") ??
|
|
72
|
+
doc?.querySelector("[data-width][data-height]");
|
|
73
|
+
if (!root) return null;
|
|
74
|
+
const width = Number.parseInt(root.getAttribute("data-width") ?? "", 10);
|
|
75
|
+
const height = Number.parseInt(root.getAttribute("data-height") ?? "", 10);
|
|
76
|
+
if (!Number.isFinite(width) || width <= 0 || !Number.isFinite(height) || height <= 0) {
|
|
77
|
+
return null;
|
|
78
|
+
}
|
|
79
|
+
return { width, height };
|
|
80
|
+
} catch {
|
|
81
|
+
return null;
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
export function resolvePreviewStageSize(
|
|
60
86
|
viewportWidth: number,
|
|
61
87
|
viewportHeight: number,
|
|
88
|
+
compositionSize: PreviewCompositionSize | null,
|
|
62
89
|
portrait: boolean | undefined,
|
|
63
90
|
): { width: number; height: number } {
|
|
64
91
|
const availableWidth = Math.max(0, viewportWidth - PREVIEW_STAGE_INSET_PX);
|
|
65
92
|
const availableHeight = Math.max(0, viewportHeight - PREVIEW_STAGE_INSET_PX);
|
|
66
|
-
const aspectRatio =
|
|
93
|
+
const aspectRatio =
|
|
94
|
+
compositionSize && compositionSize.width > 0 && compositionSize.height > 0
|
|
95
|
+
? compositionSize.width / compositionSize.height
|
|
96
|
+
: portrait
|
|
97
|
+
? 9 / 16
|
|
98
|
+
: 16 / 9;
|
|
67
99
|
|
|
68
100
|
if (availableWidth === 0 || availableHeight === 0) {
|
|
69
101
|
return { width: 0, height: 0 };
|
|
@@ -95,10 +127,12 @@ export const NLEPreview = memo(function NLEPreview({
|
|
|
95
127
|
const activeKey = getPreviewPlayerKey({ projectId, directUrl });
|
|
96
128
|
const viewportRef = useRef<HTMLDivElement>(null);
|
|
97
129
|
const stageRef = useRef<HTMLDivElement>(null);
|
|
130
|
+
const previewIframeRef = useRef<HTMLIFrameElement | null>(null);
|
|
98
131
|
useEffect(() => {
|
|
99
132
|
onStageRef?.(stageRef);
|
|
100
133
|
}, [onStageRef]);
|
|
101
|
-
const [
|
|
134
|
+
const [compositionSize, setCompositionSize] = useState<PreviewCompositionSize | null>(null);
|
|
135
|
+
const [stageSize, setStageSize] = useState(() => resolvePreviewStageSize(0, 0, null, portrait));
|
|
102
136
|
|
|
103
137
|
const zoomRef = useRef<PreviewZoomState>(loadInitialZoom());
|
|
104
138
|
const [settledZoom, setSettledZoom] = useState<PreviewZoomState>(() => zoomRef.current);
|
|
@@ -127,14 +161,29 @@ export const NLEPreview = memo(function NLEPreview({
|
|
|
127
161
|
|
|
128
162
|
const updateStageSize = () => {
|
|
129
163
|
const rect = viewport.getBoundingClientRect();
|
|
130
|
-
setStageSize(resolvePreviewStageSize(rect.width, rect.height, portrait));
|
|
164
|
+
setStageSize(resolvePreviewStageSize(rect.width, rect.height, compositionSize, portrait));
|
|
131
165
|
};
|
|
132
166
|
|
|
133
167
|
updateStageSize();
|
|
134
168
|
const observer = new ResizeObserver(updateStageSize);
|
|
135
169
|
observer.observe(viewport);
|
|
136
170
|
return () => observer.disconnect();
|
|
137
|
-
}, [portrait]);
|
|
171
|
+
}, [compositionSize, portrait]);
|
|
172
|
+
|
|
173
|
+
const updateCompositionSizeFromPreview = useCallback(() => {
|
|
174
|
+
const next = readPreviewCompositionSize(previewIframeRef.current);
|
|
175
|
+
setCompositionSize((prev) =>
|
|
176
|
+
prev?.width === next?.width && prev?.height === next?.height ? prev : next,
|
|
177
|
+
);
|
|
178
|
+
}, []);
|
|
179
|
+
|
|
180
|
+
const setPreviewIframeRef = useCallback(
|
|
181
|
+
(node: HTMLIFrameElement | null) => {
|
|
182
|
+
previewIframeRef.current = node;
|
|
183
|
+
iframeRef.current = node;
|
|
184
|
+
},
|
|
185
|
+
[iframeRef],
|
|
186
|
+
);
|
|
138
187
|
|
|
139
188
|
const stageSizeRef = useRef(stageSize);
|
|
140
189
|
stageSizeRef.current = stageSize;
|
|
@@ -403,10 +452,11 @@ export const NLEPreview = memo(function NLEPreview({
|
|
|
403
452
|
)}
|
|
404
453
|
<Player
|
|
405
454
|
key={activeKey}
|
|
406
|
-
ref={
|
|
455
|
+
ref={setPreviewIframeRef}
|
|
407
456
|
projectId={directUrl ? undefined : projectId}
|
|
408
457
|
directUrl={directUrl}
|
|
409
458
|
onLoad={() => {
|
|
459
|
+
updateCompositionSizeFromPreview();
|
|
410
460
|
onIframeLoad();
|
|
411
461
|
applyInitialZoom();
|
|
412
462
|
}}
|
|
@@ -81,7 +81,7 @@ export interface UseDomEditCommitsParams {
|
|
|
81
81
|
buildDomSelectionFromTarget: (
|
|
82
82
|
target: HTMLElement,
|
|
83
83
|
options?: { preferClipAncestor?: boolean },
|
|
84
|
-
) => DomEditSelection | null
|
|
84
|
+
) => Promise<DomEditSelection | null>;
|
|
85
85
|
}
|
|
86
86
|
|
|
87
87
|
// ── Hook ──
|
|
@@ -128,6 +128,7 @@ export function useDomEditCommits({
|
|
|
128
128
|
[fileTree, projectId, importedFontAssetsRef],
|
|
129
129
|
);
|
|
130
130
|
|
|
131
|
+
// fallow-ignore-next-line complexity
|
|
131
132
|
const persistDomEditOperations: PersistDomEditOperations = useCallback(
|
|
132
133
|
async (selection, operations, options) => {
|
|
133
134
|
const pid = projectIdRef.current;
|
|
@@ -232,6 +233,7 @@ export function useDomEditCommits({
|
|
|
232
233
|
|
|
233
234
|
// ── Position patch helper ──
|
|
234
235
|
|
|
236
|
+
// fallow-ignore-next-line complexity
|
|
235
237
|
const commitPositionPatchToHtml = useCallback(
|
|
236
238
|
(
|
|
237
239
|
selection: DomEditSelection,
|
|
@@ -244,6 +246,7 @@ export function useDomEditCommits({
|
|
|
244
246
|
coalesceKey: options.coalesceKey,
|
|
245
247
|
skipRefresh: options.skipRefresh ?? true,
|
|
246
248
|
});
|
|
249
|
+
// fallow-ignore-next-line complexity
|
|
247
250
|
}).catch((error) => {
|
|
248
251
|
const message = error instanceof Error ? error.message : "Failed to save position";
|
|
249
252
|
showToast(message);
|
|
@@ -251,6 +254,9 @@ export function useDomEditCommits({
|
|
|
251
254
|
source: "dom_edit",
|
|
252
255
|
label: options.label,
|
|
253
256
|
error_message: message,
|
|
257
|
+
target_id: selection.id ?? undefined,
|
|
258
|
+
target_selector: selection.selector ?? undefined,
|
|
259
|
+
target_source_file: selection.sourceFile ?? undefined,
|
|
254
260
|
});
|
|
255
261
|
});
|
|
256
262
|
},
|
|
@@ -333,6 +339,7 @@ export function useDomEditCommits({
|
|
|
333
339
|
|
|
334
340
|
// ── Motion commits (HTML-attribute–backed) ──
|
|
335
341
|
|
|
342
|
+
// fallow-ignore-next-line complexity
|
|
336
343
|
const handleDomMotionCommit = useCallback(
|
|
337
344
|
(
|
|
338
345
|
selection: DomEditSelection,
|
|
@@ -359,6 +366,7 @@ export function useDomEditCommits({
|
|
|
359
366
|
[commitPositionPatchToHtml, previewIframeRef, refreshDomEditSelectionFromPreview],
|
|
360
367
|
);
|
|
361
368
|
|
|
369
|
+
// fallow-ignore-next-line complexity
|
|
362
370
|
const handleDomMotionClear = useCallback(
|
|
363
371
|
(selection: DomEditSelection) => {
|
|
364
372
|
const clearPatches = buildClearMotionPatches(selection.element);
|
|
@@ -387,6 +395,7 @@ export function useDomEditCommits({
|
|
|
387
395
|
[commitPositionPatchToHtml, previewIframeRef, refreshDomEditSelectionFromPreview],
|
|
388
396
|
);
|
|
389
397
|
|
|
398
|
+
// fallow-ignore-next-line complexity
|
|
390
399
|
const handleDomEditElementDelete = useCallback(
|
|
391
400
|
async (selection: DomEditSelection) => {
|
|
392
401
|
const pid = projectIdRef.current;
|
|
@@ -231,7 +231,7 @@ export function useDomEditSession({
|
|
|
231
231
|
useEffect(() => {
|
|
232
232
|
if (!previewIframe) return;
|
|
233
233
|
|
|
234
|
-
const syncSelectionFromDocument = () => {
|
|
234
|
+
const syncSelectionFromDocument = async () => {
|
|
235
235
|
if (!STUDIO_INSPECTOR_PANELS_ENABLED || captionEditMode) return;
|
|
236
236
|
const currentSelection = domEditSelectionRef.current;
|
|
237
237
|
if (!currentSelection) return;
|
|
@@ -249,7 +249,7 @@ export function useDomEditSession({
|
|
|
249
249
|
return;
|
|
250
250
|
}
|
|
251
251
|
|
|
252
|
-
const nextSelection = buildDomSelectionFromTarget(nextElement);
|
|
252
|
+
const nextSelection = await buildDomSelectionFromTarget(nextElement);
|
|
253
253
|
if (nextSelection) {
|
|
254
254
|
applyDomSelection(nextSelection, { revealPanel: false, preserveGroup: true });
|
|
255
255
|
}
|
|
@@ -257,13 +257,13 @@ export function useDomEditSession({
|
|
|
257
257
|
|
|
258
258
|
syncPreviewHistoryHotkey(previewIframe);
|
|
259
259
|
void applyStudioManualEditsToPreviewRef.current(previewIframe);
|
|
260
|
-
syncSelectionFromDocument();
|
|
260
|
+
void syncSelectionFromDocument();
|
|
261
261
|
refreshPreviewDocumentVersion();
|
|
262
262
|
|
|
263
263
|
const handleLoad = () => {
|
|
264
264
|
syncPreviewHistoryHotkey(previewIframe);
|
|
265
265
|
void applyStudioManualEditsToPreviewRef.current(previewIframe);
|
|
266
|
-
syncSelectionFromDocument();
|
|
266
|
+
void syncSelectionFromDocument();
|
|
267
267
|
refreshPreviewDocumentVersion();
|
|
268
268
|
};
|
|
269
269
|
|
|
@@ -38,7 +38,7 @@ export interface UseDomEditTextCommitsParams {
|
|
|
38
38
|
buildDomSelectionFromTarget: (
|
|
39
39
|
target: HTMLElement,
|
|
40
40
|
options?: { preferClipAncestor?: boolean },
|
|
41
|
-
) => DomEditSelection | null
|
|
41
|
+
) => Promise<DomEditSelection | null>;
|
|
42
42
|
persistDomEditOperations: PersistDomEditOperations;
|
|
43
43
|
resolveImportedFontAsset: (fontFamilyValue: string) => ImportedFontAsset | null;
|
|
44
44
|
}
|
|
@@ -231,7 +231,7 @@ export function useDomEditTextCommits({
|
|
|
231
231
|
if (doc) {
|
|
232
232
|
const refreshed = findElementForSelection(doc, domEditSelection, activeCompPath);
|
|
233
233
|
if (refreshed) {
|
|
234
|
-
const nextSelection = buildDomSelectionFromTarget(refreshed);
|
|
234
|
+
const nextSelection = await buildDomSelectionFromTarget(refreshed);
|
|
235
235
|
if (nextSelection) {
|
|
236
236
|
applyDomSelection(nextSelection, { revealPanel: false, preserveGroup: true });
|
|
237
237
|
}
|
|
@@ -287,7 +287,7 @@ export function useDomEditTextCommits({
|
|
|
287
287
|
if (doc) {
|
|
288
288
|
const refreshed = findElementForSelection(doc, selection, activeCompPath);
|
|
289
289
|
if (refreshed) {
|
|
290
|
-
const nextSelection = buildDomSelectionFromTarget(refreshed);
|
|
290
|
+
const nextSelection = await buildDomSelectionFromTarget(refreshed);
|
|
291
291
|
if (nextSelection) {
|
|
292
292
|
applyDomSelection(nextSelection, { revealPanel: false, preserveGroup: true });
|
|
293
293
|
}
|
|
@@ -60,17 +60,19 @@ export interface UseDomSelectionReturn {
|
|
|
60
60
|
buildDomSelectionFromTarget: (
|
|
61
61
|
target: HTMLElement,
|
|
62
62
|
options?: { preferClipAncestor?: boolean },
|
|
63
|
-
) => DomEditSelection | null
|
|
63
|
+
) => Promise<DomEditSelection | null>;
|
|
64
64
|
resolveDomSelectionFromPreviewPoint: (
|
|
65
65
|
clientX: number,
|
|
66
66
|
clientY: number,
|
|
67
67
|
options?: { preferClipAncestor?: boolean },
|
|
68
|
-
) => DomEditSelection | null
|
|
68
|
+
) => Promise<DomEditSelection | null>;
|
|
69
69
|
updateDomEditHoverSelection: (selection: DomEditSelection | null) => void;
|
|
70
|
-
buildDomSelectionForTimelineElement: (
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
70
|
+
buildDomSelectionForTimelineElement: (
|
|
71
|
+
element: TimelineElement,
|
|
72
|
+
) => Promise<DomEditSelection | null>;
|
|
73
|
+
handleTimelineElementSelect: (element: TimelineElement | null) => Promise<void>;
|
|
74
|
+
refreshDomEditSelectionFromPreview: (selection: DomEditSelection) => Promise<void>;
|
|
75
|
+
refreshDomEditGroupSelectionsFromPreview: (selections: DomEditSelection[]) => Promise<void>;
|
|
74
76
|
}
|
|
75
77
|
|
|
76
78
|
// ── Hook ──
|
|
@@ -193,24 +195,34 @@ export function useDomSelection({
|
|
|
193
195
|
}, [applyDomSelection]);
|
|
194
196
|
|
|
195
197
|
const buildDomSelectionFromTarget = useCallback(
|
|
196
|
-
(
|
|
198
|
+
(
|
|
199
|
+
target: HTMLElement,
|
|
200
|
+
options?: { preferClipAncestor?: boolean; skipSourceProbe?: boolean },
|
|
201
|
+
) => {
|
|
197
202
|
return resolveDomEditSelection(target, {
|
|
198
203
|
activeCompositionPath: activeCompPath,
|
|
199
204
|
isMasterView,
|
|
200
205
|
preferClipAncestor: options?.preferClipAncestor,
|
|
206
|
+
skipSourceProbe: options?.skipSourceProbe,
|
|
207
|
+
projectId,
|
|
201
208
|
});
|
|
202
209
|
},
|
|
203
|
-
[activeCompPath, isMasterView],
|
|
210
|
+
[activeCompPath, isMasterView, projectId],
|
|
204
211
|
);
|
|
205
212
|
|
|
206
213
|
const resolveDomSelectionFromPreviewPoint = useCallback(
|
|
207
|
-
(
|
|
214
|
+
async (
|
|
215
|
+
clientX: number,
|
|
216
|
+
clientY: number,
|
|
217
|
+
options?: { preferClipAncestor?: boolean; skipSourceProbe?: boolean },
|
|
218
|
+
) => {
|
|
208
219
|
const iframe = previewIframeRef.current;
|
|
209
220
|
if (!iframe || captionEditMode) return null;
|
|
210
221
|
const target = getPreviewTargetFromPointer(iframe, clientX, clientY, activeCompPath);
|
|
211
222
|
if (!target) return null;
|
|
212
223
|
return buildDomSelectionFromTarget(target, {
|
|
213
224
|
preferClipAncestor: options?.preferClipAncestor,
|
|
225
|
+
skipSourceProbe: options?.skipSourceProbe,
|
|
214
226
|
});
|
|
215
227
|
},
|
|
216
228
|
[activeCompPath, buildDomSelectionFromTarget, captionEditMode, previewIframeRef],
|
|
@@ -223,7 +235,7 @@ export function useDomSelection({
|
|
|
223
235
|
}, []);
|
|
224
236
|
|
|
225
237
|
const buildDomSelectionForTimelineElement = useCallback(
|
|
226
|
-
(element: TimelineElement): DomEditSelection | null => {
|
|
238
|
+
async (element: TimelineElement): Promise<DomEditSelection | null> => {
|
|
227
239
|
const iframe = previewIframeRef.current;
|
|
228
240
|
let doc: Document | null = null;
|
|
229
241
|
try {
|
|
@@ -248,21 +260,21 @@ export function useDomSelection({
|
|
|
248
260
|
);
|
|
249
261
|
|
|
250
262
|
const handleTimelineElementSelect = useCallback(
|
|
251
|
-
(element: TimelineElement | null) => {
|
|
263
|
+
async (element: TimelineElement | null) => {
|
|
252
264
|
if (!STUDIO_INSPECTOR_PANELS_ENABLED) return;
|
|
253
265
|
if (!element) {
|
|
254
266
|
applyDomSelection(null, { revealPanel: false });
|
|
255
267
|
return;
|
|
256
268
|
}
|
|
257
269
|
|
|
258
|
-
const selection = buildDomSelectionForTimelineElement(element);
|
|
270
|
+
const selection = await buildDomSelectionForTimelineElement(element);
|
|
259
271
|
if (selection) applyDomSelection(selection);
|
|
260
272
|
},
|
|
261
273
|
[applyDomSelection, buildDomSelectionForTimelineElement],
|
|
262
274
|
);
|
|
263
275
|
|
|
264
276
|
const refreshDomEditSelectionFromPreview = useCallback(
|
|
265
|
-
(selection: DomEditSelection) => {
|
|
277
|
+
async (selection: DomEditSelection) => {
|
|
266
278
|
const iframe = previewIframeRef.current;
|
|
267
279
|
let doc: Document | null = null;
|
|
268
280
|
try {
|
|
@@ -275,7 +287,7 @@ export function useDomSelection({
|
|
|
275
287
|
const element = findElementForSelection(doc, selection, activeCompPath);
|
|
276
288
|
if (!element) return;
|
|
277
289
|
|
|
278
|
-
const nextSelection = buildDomSelectionFromTarget(element);
|
|
290
|
+
const nextSelection = await buildDomSelectionFromTarget(element);
|
|
279
291
|
if (nextSelection) {
|
|
280
292
|
applyDomSelection(nextSelection, {
|
|
281
293
|
revealPanel: false,
|
|
@@ -287,7 +299,7 @@ export function useDomSelection({
|
|
|
287
299
|
);
|
|
288
300
|
|
|
289
301
|
const refreshDomEditGroupSelectionsFromPreview = useCallback(
|
|
290
|
-
(selections: DomEditSelection[]) => {
|
|
302
|
+
async (selections: DomEditSelection[]) => {
|
|
291
303
|
const iframe = previewIframeRef.current;
|
|
292
304
|
let doc: Document | null = null;
|
|
293
305
|
try {
|
|
@@ -301,7 +313,7 @@ export function useDomSelection({
|
|
|
301
313
|
for (const selection of selections) {
|
|
302
314
|
const element = findElementForSelection(doc, selection, activeCompPath);
|
|
303
315
|
if (!element) continue;
|
|
304
|
-
const nextSelection = buildDomSelectionFromTarget(element);
|
|
316
|
+
const nextSelection = await buildDomSelectionFromTarget(element);
|
|
305
317
|
if (nextSelection) nextGroup.push(nextSelection);
|
|
306
318
|
}
|
|
307
319
|
if (nextGroup.length === 0) return;
|
|
@@ -20,8 +20,8 @@ export interface UsePreviewInteractionParams {
|
|
|
20
20
|
resolveDomSelectionFromPreviewPoint: (
|
|
21
21
|
clientX: number,
|
|
22
22
|
clientY: number,
|
|
23
|
-
options?: { preferClipAncestor?: boolean },
|
|
24
|
-
) => DomEditSelection | null
|
|
23
|
+
options?: { preferClipAncestor?: boolean; skipSourceProbe?: boolean },
|
|
24
|
+
) => Promise<DomEditSelection | null>;
|
|
25
25
|
updateDomEditHoverSelection: (selection: DomEditSelection | null) => void;
|
|
26
26
|
|
|
27
27
|
onClickToSource?: (selection: DomEditSelection) => void;
|
|
@@ -40,9 +40,9 @@ export function usePreviewInteraction({
|
|
|
40
40
|
onClickToSource,
|
|
41
41
|
}: UsePreviewInteractionParams) {
|
|
42
42
|
const handlePreviewCanvasMouseDown = useCallback(
|
|
43
|
-
(e: React.MouseEvent<HTMLDivElement>, options?: { preferClipAncestor?: boolean }) => {
|
|
43
|
+
async (e: React.MouseEvent<HTMLDivElement>, options?: { preferClipAncestor?: boolean }) => {
|
|
44
44
|
if (!STUDIO_PREVIEW_SELECTION_ENABLED || captionEditMode || compositionLoading) return;
|
|
45
|
-
const nextSelection = resolveDomSelectionFromPreviewPoint(e.clientX, e.clientY, {
|
|
45
|
+
const nextSelection = await resolveDomSelectionFromPreviewPoint(e.clientX, e.clientY, {
|
|
46
46
|
preferClipAncestor: options?.preferClipAncestor ?? false,
|
|
47
47
|
});
|
|
48
48
|
if (!nextSelection) {
|
|
@@ -66,14 +66,15 @@ export function usePreviewInteraction({
|
|
|
66
66
|
);
|
|
67
67
|
|
|
68
68
|
const handlePreviewCanvasPointerMove = useCallback(
|
|
69
|
-
(e: React.PointerEvent<HTMLDivElement>, options?: { preferClipAncestor?: boolean }) => {
|
|
69
|
+
async (e: React.PointerEvent<HTMLDivElement>, options?: { preferClipAncestor?: boolean }) => {
|
|
70
70
|
if (!STUDIO_PREVIEW_SELECTION_ENABLED || captionEditMode || compositionLoading) {
|
|
71
71
|
updateDomEditHoverSelection(null);
|
|
72
72
|
return null;
|
|
73
73
|
}
|
|
74
74
|
|
|
75
|
-
const nextSelection = resolveDomSelectionFromPreviewPoint(e.clientX, e.clientY, {
|
|
75
|
+
const nextSelection = await resolveDomSelectionFromPreviewPoint(e.clientX, e.clientY, {
|
|
76
76
|
preferClipAncestor: options?.preferClipAncestor ?? false,
|
|
77
|
+
skipSourceProbe: true,
|
|
77
78
|
});
|
|
78
79
|
updateDomEditHoverSelection(nextSelection);
|
|
79
80
|
return nextSelection;
|
|
@@ -25,7 +25,7 @@ interface UseStudioUrlStateParams {
|
|
|
25
25
|
buildDomSelectionFromTarget: (
|
|
26
26
|
target: HTMLElement,
|
|
27
27
|
options?: { preferClipAncestor?: boolean },
|
|
28
|
-
) => DomEditSelection | null
|
|
28
|
+
) => Promise<DomEditSelection | null>;
|
|
29
29
|
applyDomSelection: (
|
|
30
30
|
selection: DomEditSelection | null,
|
|
31
31
|
options?: {
|
|
@@ -140,10 +140,11 @@ export function useStudioUrlState({
|
|
|
140
140
|
return;
|
|
141
141
|
}
|
|
142
142
|
|
|
143
|
-
const selection = buildDomSelectionFromTarget(element, { preferClipAncestor: false });
|
|
144
|
-
applyDomSelection(selection, { revealPanel: false });
|
|
145
143
|
hydratedSelectionRef.current = true;
|
|
146
144
|
pendingSelectionRef.current = null;
|
|
145
|
+
void buildDomSelectionFromTarget(element, { preferClipAncestor: false }).then((selection) => {
|
|
146
|
+
applyDomSelection(selection, { revealPanel: false });
|
|
147
|
+
});
|
|
147
148
|
}, [
|
|
148
149
|
activeCompPath,
|
|
149
150
|
applyDomSelection,
|