@hyperframes/studio 0.8.178 → 0.8.180
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-Dfw61RJK.js → hyperframes-player-1wdLVP-x.js} +1 -1
- package/dist/assets/{index-eTRj5rY2.js → index-CaWPPTQ1.js} +1 -1
- package/dist/assets/{index-Bi6yVTq9.js → index-mdtW0Ug-.js} +150 -150
- package/dist/index.d.ts +1 -1
- package/dist/index.html +1 -1
- package/dist/index.js +10 -48
- package/package.json +8 -8
- package/src/hooks/previewPromotionSelection.test.tsx +5 -6
- package/src/hooks/useDomEditPreviewSync.test.ts +1 -5
- package/src/hooks/useDomEditPreviewSync.ts +9 -58
- package/src/hooks/useDomEditSession.ts +1 -5
- package/src/hooks/useDomEditWiring.ts +6 -16
- package/src/hooks/useDomSelection.test.ts +62 -0
- package/src/hooks/useDomSelection.ts +5 -4
- package/src/hooks/useDomSelectionTypes.ts +4 -2
package/dist/index.d.ts
CHANGED
|
@@ -3463,7 +3463,7 @@ declare function useDomEditSession({ projectId, activeCompPath, compIdToSrc, cap
|
|
|
3463
3463
|
handlePreviewCanvasPointerLeave: () => void;
|
|
3464
3464
|
applyDomSelection: (selection: DomEditSelection | null, options?: ApplyDomSelectionOptions) => void;
|
|
3465
3465
|
clearDomSelection: () => void;
|
|
3466
|
-
refreshDomEditSelectionFromPreview: (selection: DomEditSelection) => Promise<void>;
|
|
3466
|
+
refreshDomEditSelectionFromPreview: (selection: DomEditSelection, iframe?: HTMLIFrameElement | null) => Promise<void>;
|
|
3467
3467
|
handleDomStyleCommit: (property: string, value: string) => Promise<DomEditCommitOutcome>;
|
|
3468
3468
|
handleDomStyleCommitForSelection: (selection: DomEditSelection, propertyOrStylesAsOnePatch: string | Record<string, string>, value?: string) => Promise<DomEditCommitOutcome>;
|
|
3469
3469
|
handleDomAttributeCommit: (attr: string, value: string) => Promise<void>;
|
package/dist/index.html
CHANGED
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
document.documentElement.dataset.theme = "paper";
|
|
15
15
|
}
|
|
16
16
|
</script>
|
|
17
|
-
<script type="module" crossorigin src="/assets/index-
|
|
17
|
+
<script type="module" crossorigin src="/assets/index-mdtW0Ug-.js"></script>
|
|
18
18
|
<link rel="stylesheet" crossorigin href="/assets/index-CESvLzz0.css">
|
|
19
19
|
</head>
|
|
20
20
|
<body>
|
package/dist/index.js
CHANGED
|
@@ -79948,8 +79948,9 @@ function useDomSelection({
|
|
|
79948
79948
|
});
|
|
79949
79949
|
const refreshDomEditSelectionFromPreview = useCallback125(
|
|
79950
79950
|
// fallow-ignore-next-line complexity
|
|
79951
|
-
async (selection) => {
|
|
79952
|
-
const
|
|
79951
|
+
async (selection, iframe = previewIframeRef.current) => {
|
|
79952
|
+
const stillSelected = () => domEditSelectionsTargetSame(domEditSelectionRef.current, selection);
|
|
79953
|
+
if (!stillSelected()) return;
|
|
79953
79954
|
let doc = null;
|
|
79954
79955
|
try {
|
|
79955
79956
|
doc = iframe?.contentDocument ?? null;
|
|
@@ -79972,7 +79973,7 @@ function useDomSelection({
|
|
|
79972
79973
|
return;
|
|
79973
79974
|
}
|
|
79974
79975
|
const nextSelection = await buildDomSelectionFromTarget(element, { previous: selection });
|
|
79975
|
-
if (nextSelection) {
|
|
79976
|
+
if (nextSelection && stillSelected()) {
|
|
79976
79977
|
applyDomSelection(nextSelection, {
|
|
79977
79978
|
revealPanel: false,
|
|
79978
79979
|
preserveGroup: true
|
|
@@ -80100,7 +80101,6 @@ function useDomSelection({
|
|
|
80100
80101
|
buildDomSelectionForTimelineElement,
|
|
80101
80102
|
handleTimelineElementSelect,
|
|
80102
80103
|
refreshDomEditSelectionFromPreview,
|
|
80103
|
-
refreshDomEditGroupSelectionsFromPreview,
|
|
80104
80104
|
applyMarqueeSelection
|
|
80105
80105
|
};
|
|
80106
80106
|
}
|
|
@@ -83658,14 +83658,10 @@ import { useCallback as useCallback142, useEffect as useEffect119, useRef as use
|
|
|
83658
83658
|
import { useEffect as useEffect118, useRef as useRef149 } from "react";
|
|
83659
83659
|
function useDomEditPreviewSync({
|
|
83660
83660
|
previewIframe,
|
|
83661
|
-
activeCompPath,
|
|
83662
83661
|
captionEditMode,
|
|
83663
83662
|
domEditSelectionRef,
|
|
83664
|
-
domEditGroupSelectionsRef,
|
|
83665
83663
|
domEditSelection,
|
|
83666
|
-
|
|
83667
|
-
refreshDomEditGroupSelectionsFromPreview,
|
|
83668
|
-
buildDomSelectionFromTarget,
|
|
83664
|
+
refreshDomEditSelectionFromPreview,
|
|
83669
83665
|
refreshPreviewDocumentVersion,
|
|
83670
83666
|
syncPreviewHotkeys,
|
|
83671
83667
|
applyStudioManualEditsToPreviewRef,
|
|
@@ -83686,26 +83682,7 @@ function useDomEditPreviewSync({
|
|
|
83686
83682
|
}
|
|
83687
83683
|
if (!doc) return;
|
|
83688
83684
|
reapplyPositionEditsAfterSeek(doc);
|
|
83689
|
-
|
|
83690
|
-
if (!nextElement) {
|
|
83691
|
-
const group = domEditGroupSelectionsRef.current;
|
|
83692
|
-
logSelect("preview-sync-lost", {
|
|
83693
|
-
target: currentSelection.selector ?? currentSelection.id ?? null,
|
|
83694
|
-
group: group.length
|
|
83695
|
-
});
|
|
83696
|
-
if (group.length > 1) {
|
|
83697
|
-
await refreshDomEditGroupSelectionsFromPreview(group);
|
|
83698
|
-
return;
|
|
83699
|
-
}
|
|
83700
|
-
applyDomSelection(null, { revealPanel: false });
|
|
83701
|
-
return;
|
|
83702
|
-
}
|
|
83703
|
-
const nextSelection = await buildDomSelectionFromTarget(nextElement, {
|
|
83704
|
-
previous: currentSelection
|
|
83705
|
-
});
|
|
83706
|
-
if (nextSelection) {
|
|
83707
|
-
applyDomSelection(nextSelection, { revealPanel: false, preserveGroup: true });
|
|
83708
|
-
}
|
|
83685
|
+
await refreshDomEditSelectionFromPreview(currentSelection, previewIframe);
|
|
83709
83686
|
};
|
|
83710
83687
|
syncPreviewHotkeys(previewIframe);
|
|
83711
83688
|
void applyStudioManualEditsToPreviewRef.current(previewIframe);
|
|
@@ -83719,14 +83696,10 @@ function useDomEditPreviewSync({
|
|
|
83719
83696
|
};
|
|
83720
83697
|
return onPreviewContentReplaced(previewIframe, handleLoad);
|
|
83721
83698
|
}, [
|
|
83722
|
-
activeCompPath,
|
|
83723
|
-
applyDomSelection,
|
|
83724
|
-
buildDomSelectionFromTarget,
|
|
83725
83699
|
captionEditMode,
|
|
83726
|
-
domEditGroupSelectionsRef,
|
|
83727
83700
|
domEditSelectionRef,
|
|
83728
83701
|
previewIframe,
|
|
83729
|
-
|
|
83702
|
+
refreshDomEditSelectionFromPreview,
|
|
83730
83703
|
refreshPreviewDocumentVersion,
|
|
83731
83704
|
syncPreviewHotkeys,
|
|
83732
83705
|
applyStudioManualEditsToPreviewRef,
|
|
@@ -84106,8 +84079,7 @@ function useDomEditWiring(params) {
|
|
|
84106
84079
|
activeCompPath,
|
|
84107
84080
|
domEditSelection,
|
|
84108
84081
|
domEditSelectionRef,
|
|
84109
|
-
|
|
84110
|
-
refreshDomEditGroupSelectionsFromPreview,
|
|
84082
|
+
refreshDomEditSelectionFromPreview,
|
|
84111
84083
|
previewIframeRef,
|
|
84112
84084
|
previewIframe,
|
|
84113
84085
|
captionEditMode,
|
|
@@ -84118,8 +84090,6 @@ function useDomEditWiring(params) {
|
|
|
84118
84090
|
refreshPreviewDocumentVersion,
|
|
84119
84091
|
syncPreviewHotkeys,
|
|
84120
84092
|
applyStudioManualEditsToPreviewRef,
|
|
84121
|
-
applyDomSelection,
|
|
84122
|
-
buildDomSelectionFromTarget,
|
|
84123
84093
|
openSourceForSelection,
|
|
84124
84094
|
updateGsapProperty,
|
|
84125
84095
|
updateGsapMeta,
|
|
@@ -84216,14 +84186,10 @@ function useDomEditWiring(params) {
|
|
|
84216
84186
|
});
|
|
84217
84187
|
useDomEditPreviewSync({
|
|
84218
84188
|
previewIframe,
|
|
84219
|
-
activeCompPath,
|
|
84220
84189
|
captionEditMode,
|
|
84221
84190
|
domEditSelectionRef,
|
|
84222
|
-
domEditGroupSelectionsRef,
|
|
84223
84191
|
domEditSelection,
|
|
84224
|
-
|
|
84225
|
-
refreshDomEditGroupSelectionsFromPreview,
|
|
84226
|
-
buildDomSelectionFromTarget,
|
|
84192
|
+
refreshDomEditSelectionFromPreview,
|
|
84227
84193
|
refreshPreviewDocumentVersion,
|
|
84228
84194
|
syncPreviewHotkeys,
|
|
84229
84195
|
applyStudioManualEditsToPreviewRef,
|
|
@@ -86231,7 +86197,6 @@ function useDomEditSession({
|
|
|
86231
86197
|
buildDomSelectionForTimelineElement,
|
|
86232
86198
|
handleTimelineElementSelect,
|
|
86233
86199
|
refreshDomEditSelectionFromPreview,
|
|
86234
|
-
refreshDomEditGroupSelectionsFromPreview,
|
|
86235
86200
|
applyMarqueeSelection
|
|
86236
86201
|
} = useDomSelection({
|
|
86237
86202
|
projectId,
|
|
@@ -86471,8 +86436,7 @@ function useDomEditSession({
|
|
|
86471
86436
|
activeCompPath,
|
|
86472
86437
|
domEditSelection,
|
|
86473
86438
|
domEditSelectionRef,
|
|
86474
|
-
|
|
86475
|
-
refreshDomEditGroupSelectionsFromPreview,
|
|
86439
|
+
refreshDomEditSelectionFromPreview,
|
|
86476
86440
|
previewIframeRef,
|
|
86477
86441
|
previewIframe,
|
|
86478
86442
|
captionEditMode: previewCaptionEditMode,
|
|
@@ -86483,8 +86447,6 @@ function useDomEditSession({
|
|
|
86483
86447
|
refreshPreviewDocumentVersion,
|
|
86484
86448
|
syncPreviewHotkeys,
|
|
86485
86449
|
applyStudioManualEditsToPreviewRef,
|
|
86486
|
-
applyDomSelection,
|
|
86487
|
-
buildDomSelectionFromTarget,
|
|
86488
86450
|
openSourceForSelection,
|
|
86489
86451
|
...gsapScriptEdits,
|
|
86490
86452
|
handleDomManualEditsReset
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@hyperframes/studio",
|
|
3
|
-
"version": "0.8.
|
|
3
|
+
"version": "0.8.180",
|
|
4
4
|
"description": "",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -59,12 +59,12 @@
|
|
|
59
59
|
"dockview-react": "8.3.1",
|
|
60
60
|
"gsap": "^3.13.0",
|
|
61
61
|
"mediabunny": "^1.45.3",
|
|
62
|
-
"@hyperframes/core": "0.8.
|
|
63
|
-
"@hyperframes/
|
|
64
|
-
"@hyperframes/
|
|
65
|
-
"@hyperframes/
|
|
66
|
-
"@hyperframes/
|
|
67
|
-
"@hyperframes/
|
|
62
|
+
"@hyperframes/core": "0.8.180",
|
|
63
|
+
"@hyperframes/sdk": "0.8.180",
|
|
64
|
+
"@hyperframes/parsers": "0.8.180",
|
|
65
|
+
"@hyperframes/shader-transitions": "0.8.180",
|
|
66
|
+
"@hyperframes/player": "0.8.180",
|
|
67
|
+
"@hyperframes/studio-server": "0.8.180"
|
|
68
68
|
},
|
|
69
69
|
"devDependencies": {
|
|
70
70
|
"@tailwindcss/vite": "^4.3.3",
|
|
@@ -81,7 +81,7 @@
|
|
|
81
81
|
"vite": "^6.4.2",
|
|
82
82
|
"vitest": "^4.1.11",
|
|
83
83
|
"zustand": "^5.0.0",
|
|
84
|
-
"@hyperframes/producer": "0.8.
|
|
84
|
+
"@hyperframes/producer": "0.8.180"
|
|
85
85
|
},
|
|
86
86
|
"peerDependencies": {
|
|
87
87
|
"react": "19",
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
import React, { act } from "react";
|
|
3
3
|
import { createRoot } from "react-dom/client";
|
|
4
4
|
import { afterEach, describe, expect, it, vi } from "vitest";
|
|
5
|
-
import type
|
|
5
|
+
import { findElementForSelection, type DomEditSelection } from "../components/editor/domEditing";
|
|
6
6
|
import { resolveElementForOverlay } from "../components/editor/domEditOverlayGeometry";
|
|
7
7
|
import {
|
|
8
8
|
makePreview,
|
|
@@ -44,14 +44,13 @@ function mountHost(followPromotions: boolean) {
|
|
|
44
44
|
const live = useLivePreviewIframe(host);
|
|
45
45
|
useDomEditPreviewSync({
|
|
46
46
|
previewIframe: followPromotions ? live : host,
|
|
47
|
-
activeCompPath: null,
|
|
48
47
|
captionEditMode: false,
|
|
49
48
|
domEditSelectionRef: selectionRef,
|
|
50
|
-
domEditGroupSelectionsRef: { current: [] },
|
|
51
49
|
domEditSelection: selectionRef.current,
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
50
|
+
refreshDomEditSelectionFromPreview: async (selection, iframe) => {
|
|
51
|
+
const element = findElementForSelection(iframe.contentDocument!, selection, null);
|
|
52
|
+
selectionRef.current = element ? selectionOf(element) : null;
|
|
53
|
+
},
|
|
55
54
|
refreshPreviewDocumentVersion: () => {},
|
|
56
55
|
syncPreviewHotkeys: () => {},
|
|
57
56
|
applyStudioManualEditsToPreviewRef: { current: async () => {} },
|
|
@@ -25,14 +25,10 @@ describe("useDomEditPreviewSync", () => {
|
|
|
25
25
|
function Harness() {
|
|
26
26
|
useDomEditPreviewSync({
|
|
27
27
|
previewIframe: iframe,
|
|
28
|
-
activeCompPath: null,
|
|
29
28
|
captionEditMode: false,
|
|
30
29
|
domEditSelectionRef: { current: null },
|
|
31
|
-
domEditGroupSelectionsRef: { current: [] },
|
|
32
30
|
domEditSelection: null,
|
|
33
|
-
|
|
34
|
-
applyDomSelection: () => {},
|
|
35
|
-
buildDomSelectionFromTarget: async () => null,
|
|
31
|
+
refreshDomEditSelectionFromPreview: async () => {},
|
|
36
32
|
refreshPreviewDocumentVersion: refreshVersion,
|
|
37
33
|
syncPreviewHotkeys: () => {},
|
|
38
34
|
applyStudioManualEditsToPreviewRef: { current: applyManualEdits },
|
|
@@ -4,31 +4,22 @@
|
|
|
4
4
|
* Extracted from useDomEditSession to keep file sizes under the 600-line limit.
|
|
5
5
|
*/
|
|
6
6
|
import { useEffect, useRef } from "react";
|
|
7
|
-
import {
|
|
7
|
+
import type { DomEditSelection } from "../components/editor/domEditing";
|
|
8
8
|
import { reapplyPositionEditsAfterSeek } from "../components/editor/manualEdits";
|
|
9
9
|
import { useDockLayoutStore } from "../components/dock/dockLayoutStore";
|
|
10
10
|
import type { PatchTarget } from "../utils/sourcePatcher";
|
|
11
|
-
import { logSelect } from "../utils/selectDebug";
|
|
12
11
|
import { onPreviewContentReplaced } from "../player/sceneSwap";
|
|
13
|
-
import type { ResolveDomSelectionOptions } from "./useDomSelectionTypes";
|
|
14
12
|
|
|
15
13
|
interface UseDomEditPreviewSyncParams {
|
|
16
14
|
previewIframe: HTMLIFrameElement | null;
|
|
17
|
-
activeCompPath: string | null;
|
|
18
15
|
captionEditMode: boolean;
|
|
19
16
|
domEditSelectionRef: React.MutableRefObject<DomEditSelection | null>;
|
|
20
|
-
domEditGroupSelectionsRef: React.MutableRefObject<DomEditSelection[]>;
|
|
21
17
|
domEditSelection: DomEditSelection | null;
|
|
22
|
-
/** Re-resolves
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
) => void;
|
|
28
|
-
buildDomSelectionFromTarget: (
|
|
29
|
-
element: HTMLElement,
|
|
30
|
-
options?: Pick<ResolveDomSelectionOptions, "previous">,
|
|
31
|
-
) => Promise<DomEditSelection | null>;
|
|
18
|
+
/** Re-resolves the selection against the given preview, unless it was deselected meanwhile. */
|
|
19
|
+
refreshDomEditSelectionFromPreview: (
|
|
20
|
+
selection: DomEditSelection,
|
|
21
|
+
iframe: HTMLIFrameElement,
|
|
22
|
+
) => Promise<void>;
|
|
32
23
|
refreshPreviewDocumentVersion: () => void;
|
|
33
24
|
syncPreviewHotkeys: (iframe: HTMLIFrameElement | null) => void;
|
|
34
25
|
applyStudioManualEditsToPreviewRef: React.MutableRefObject<
|
|
@@ -40,14 +31,10 @@ interface UseDomEditPreviewSyncParams {
|
|
|
40
31
|
|
|
41
32
|
export function useDomEditPreviewSync({
|
|
42
33
|
previewIframe,
|
|
43
|
-
activeCompPath,
|
|
44
34
|
captionEditMode,
|
|
45
35
|
domEditSelectionRef,
|
|
46
|
-
domEditGroupSelectionsRef,
|
|
47
36
|
domEditSelection,
|
|
48
|
-
|
|
49
|
-
refreshDomEditGroupSelectionsFromPreview,
|
|
50
|
-
buildDomSelectionFromTarget,
|
|
37
|
+
refreshDomEditSelectionFromPreview,
|
|
51
38
|
refreshPreviewDocumentVersion,
|
|
52
39
|
syncPreviewHotkeys,
|
|
53
40
|
applyStudioManualEditsToPreviewRef,
|
|
@@ -73,39 +60,7 @@ export function useDomEditPreviewSync({
|
|
|
73
60
|
if (!doc) return;
|
|
74
61
|
|
|
75
62
|
reapplyPositionEditsAfterSeek(doc);
|
|
76
|
-
|
|
77
|
-
const nextElement = findElementForSelection(doc, currentSelection, activeCompPath);
|
|
78
|
-
if (!nextElement) {
|
|
79
|
-
// The selected element no longer resolves in the (re-synced) document
|
|
80
|
-
// — comp/hot reload, activeCompPath swap, or post-save replacement.
|
|
81
|
-
// Clear so overlay geometry isn't computed on a stale, detached node.
|
|
82
|
-
// (Drag-release-in-gray-zone is handled separately by
|
|
83
|
-
// suppressNextBoxClickRef; the dragged element still resolves here.)
|
|
84
|
-
//
|
|
85
|
-
// One lost member is not the whole selection though. A multi-select that
|
|
86
|
-
// loses its primary here used to be wiped entirely, so moving a group and
|
|
87
|
-
// having any one of its elements fail to re-resolve deselected all of
|
|
88
|
-
// them. Re-resolve the group instead and keep whoever survived; it only
|
|
89
|
-
// clears when nobody did.
|
|
90
|
-
const group = domEditGroupSelectionsRef.current;
|
|
91
|
-
logSelect("preview-sync-lost", {
|
|
92
|
-
target: currentSelection.selector ?? currentSelection.id ?? null,
|
|
93
|
-
group: group.length,
|
|
94
|
-
});
|
|
95
|
-
if (group.length > 1) {
|
|
96
|
-
await refreshDomEditGroupSelectionsFromPreview(group);
|
|
97
|
-
return;
|
|
98
|
-
}
|
|
99
|
-
applyDomSelection(null, { revealPanel: false });
|
|
100
|
-
return;
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
const nextSelection = await buildDomSelectionFromTarget(nextElement, {
|
|
104
|
-
previous: currentSelection,
|
|
105
|
-
});
|
|
106
|
-
if (nextSelection) {
|
|
107
|
-
applyDomSelection(nextSelection, { revealPanel: false, preserveGroup: true });
|
|
108
|
-
}
|
|
63
|
+
await refreshDomEditSelectionFromPreview(currentSelection, previewIframe);
|
|
109
64
|
};
|
|
110
65
|
|
|
111
66
|
syncPreviewHotkeys(previewIframe);
|
|
@@ -122,14 +77,10 @@ export function useDomEditPreviewSync({
|
|
|
122
77
|
|
|
123
78
|
return onPreviewContentReplaced(previewIframe, handleLoad);
|
|
124
79
|
}, [
|
|
125
|
-
activeCompPath,
|
|
126
|
-
applyDomSelection,
|
|
127
|
-
buildDomSelectionFromTarget,
|
|
128
80
|
captionEditMode,
|
|
129
|
-
domEditGroupSelectionsRef,
|
|
130
81
|
domEditSelectionRef,
|
|
131
82
|
previewIframe,
|
|
132
|
-
|
|
83
|
+
refreshDomEditSelectionFromPreview,
|
|
133
84
|
refreshPreviewDocumentVersion,
|
|
134
85
|
syncPreviewHotkeys,
|
|
135
86
|
applyStudioManualEditsToPreviewRef,
|
|
@@ -122,7 +122,6 @@ export function useDomEditSession({
|
|
|
122
122
|
buildDomSelectionForTimelineElement,
|
|
123
123
|
handleTimelineElementSelect,
|
|
124
124
|
refreshDomEditSelectionFromPreview,
|
|
125
|
-
refreshDomEditGroupSelectionsFromPreview,
|
|
126
125
|
applyMarqueeSelection,
|
|
127
126
|
} = useDomSelection({
|
|
128
127
|
projectId,
|
|
@@ -394,8 +393,7 @@ export function useDomEditSession({
|
|
|
394
393
|
activeCompPath,
|
|
395
394
|
domEditSelection,
|
|
396
395
|
domEditSelectionRef,
|
|
397
|
-
|
|
398
|
-
refreshDomEditGroupSelectionsFromPreview,
|
|
396
|
+
refreshDomEditSelectionFromPreview,
|
|
399
397
|
previewIframeRef,
|
|
400
398
|
previewIframe,
|
|
401
399
|
captionEditMode: previewCaptionEditMode,
|
|
@@ -406,8 +404,6 @@ export function useDomEditSession({
|
|
|
406
404
|
refreshPreviewDocumentVersion,
|
|
407
405
|
syncPreviewHotkeys,
|
|
408
406
|
applyStudioManualEditsToPreviewRef,
|
|
409
|
-
applyDomSelection,
|
|
410
|
-
buildDomSelectionFromTarget,
|
|
411
407
|
openSourceForSelection,
|
|
412
408
|
...gsapScriptEdits,
|
|
413
409
|
handleDomManualEditsReset,
|
|
@@ -23,8 +23,10 @@ export interface UseDomEditWiringParams {
|
|
|
23
23
|
activeCompPath: string | null;
|
|
24
24
|
domEditSelection: DomEditSelection | null;
|
|
25
25
|
domEditSelectionRef: React.MutableRefObject<DomEditSelection | null>;
|
|
26
|
-
|
|
27
|
-
|
|
26
|
+
refreshDomEditSelectionFromPreview: (
|
|
27
|
+
selection: DomEditSelection,
|
|
28
|
+
iframe: HTMLIFrameElement,
|
|
29
|
+
) => Promise<void>;
|
|
28
30
|
previewIframeRef: React.RefObject<HTMLIFrameElement | null>;
|
|
29
31
|
previewIframe: HTMLIFrameElement | null;
|
|
30
32
|
captionEditMode: boolean;
|
|
@@ -37,11 +39,6 @@ export interface UseDomEditWiringParams {
|
|
|
37
39
|
applyStudioManualEditsToPreviewRef: React.MutableRefObject<
|
|
38
40
|
(iframe: HTMLIFrameElement) => Promise<void>
|
|
39
41
|
>;
|
|
40
|
-
applyDomSelection: (
|
|
41
|
-
selection: DomEditSelection | null,
|
|
42
|
-
options?: { revealPanel?: boolean; preserveGroup?: boolean },
|
|
43
|
-
) => void;
|
|
44
|
-
buildDomSelectionFromTarget: (element: HTMLElement) => Promise<DomEditSelection | null>;
|
|
45
42
|
openSourceForSelection?: (sourceFile: string, target: PatchTarget) => void;
|
|
46
43
|
// GSAP script commit ops (from useGsapScriptCommits)
|
|
47
44
|
updateGsapProperty: (
|
|
@@ -117,8 +114,7 @@ export function useDomEditWiring(params: UseDomEditWiringParams) {
|
|
|
117
114
|
activeCompPath,
|
|
118
115
|
domEditSelection,
|
|
119
116
|
domEditSelectionRef,
|
|
120
|
-
|
|
121
|
-
refreshDomEditGroupSelectionsFromPreview,
|
|
117
|
+
refreshDomEditSelectionFromPreview,
|
|
122
118
|
previewIframeRef,
|
|
123
119
|
previewIframe,
|
|
124
120
|
captionEditMode,
|
|
@@ -129,8 +125,6 @@ export function useDomEditWiring(params: UseDomEditWiringParams) {
|
|
|
129
125
|
refreshPreviewDocumentVersion,
|
|
130
126
|
syncPreviewHotkeys,
|
|
131
127
|
applyStudioManualEditsToPreviewRef,
|
|
132
|
-
applyDomSelection,
|
|
133
|
-
buildDomSelectionFromTarget,
|
|
134
128
|
openSourceForSelection,
|
|
135
129
|
updateGsapProperty,
|
|
136
130
|
updateGsapMeta,
|
|
@@ -251,14 +245,10 @@ export function useDomEditWiring(params: UseDomEditWiringParams) {
|
|
|
251
245
|
|
|
252
246
|
useDomEditPreviewSync({
|
|
253
247
|
previewIframe,
|
|
254
|
-
activeCompPath,
|
|
255
248
|
captionEditMode,
|
|
256
249
|
domEditSelectionRef,
|
|
257
|
-
domEditGroupSelectionsRef,
|
|
258
250
|
domEditSelection,
|
|
259
|
-
|
|
260
|
-
refreshDomEditGroupSelectionsFromPreview,
|
|
261
|
-
buildDomSelectionFromTarget,
|
|
251
|
+
refreshDomEditSelectionFromPreview,
|
|
262
252
|
refreshPreviewDocumentVersion,
|
|
263
253
|
syncPreviewHotkeys,
|
|
264
254
|
applyStudioManualEditsToPreviewRef,
|
|
@@ -326,6 +326,68 @@ describe("useDomSelection", () => {
|
|
|
326
326
|
harness.cleanup();
|
|
327
327
|
});
|
|
328
328
|
|
|
329
|
+
describe("a save's resync after the user moved on", () => {
|
|
330
|
+
function selectHeadlineInPreview() {
|
|
331
|
+
const doc = document.implementation.createHTMLDocument("");
|
|
332
|
+
const element = doc.body.appendChild(
|
|
333
|
+
Object.assign(doc.createElement("div"), { id: "headline" }),
|
|
334
|
+
);
|
|
335
|
+
const headline = makeSelection("Headline", element);
|
|
336
|
+
const harness = renderHarness(
|
|
337
|
+
{ activeCompPath: "index.html", projectId: "project-1", refreshKey: 0 },
|
|
338
|
+
{ previewDoc: doc },
|
|
339
|
+
);
|
|
340
|
+
act(() => harness.current().applyDomSelection(headline));
|
|
341
|
+
return { headline, harness };
|
|
342
|
+
}
|
|
343
|
+
|
|
344
|
+
it("keeps a deselect made while the save was in flight", async () => {
|
|
345
|
+
const { headline, harness } = selectHeadlineInPreview();
|
|
346
|
+
// Escape after a crop's release, before its save returns.
|
|
347
|
+
act(() => harness.current().applyDomSelection(null, { revealPanel: false }));
|
|
348
|
+
|
|
349
|
+
await act(() => harness.current().refreshDomEditSelectionFromPreview(headline));
|
|
350
|
+
|
|
351
|
+
expect(harness.current().domEditSelection).toBeNull();
|
|
352
|
+
harness.cleanup();
|
|
353
|
+
});
|
|
354
|
+
|
|
355
|
+
it.each([
|
|
356
|
+
["still in", false],
|
|
357
|
+
["gone from", true],
|
|
358
|
+
])(
|
|
359
|
+
"keeps a different pick made while the save was in flight, the saved element %s the preview",
|
|
360
|
+
async (_, removed) => {
|
|
361
|
+
const { headline, harness } = selectHeadlineInPreview();
|
|
362
|
+
const card = makeSelection(
|
|
363
|
+
"Card",
|
|
364
|
+
Object.assign(document.createElement("div"), { id: "card" }),
|
|
365
|
+
);
|
|
366
|
+
act(() => harness.current().applyDomSelection(card));
|
|
367
|
+
if (removed) headline.element.remove();
|
|
368
|
+
|
|
369
|
+
await act(() => harness.current().refreshDomEditSelectionFromPreview(headline));
|
|
370
|
+
|
|
371
|
+
expect(harness.current().domEditSelection).toBe(card);
|
|
372
|
+
harness.cleanup();
|
|
373
|
+
},
|
|
374
|
+
);
|
|
375
|
+
|
|
376
|
+
it("keeps a deselect made while the resync was rebuilding the selection", async () => {
|
|
377
|
+
const { headline, harness } = selectHeadlineInPreview();
|
|
378
|
+
let resync!: Promise<void>;
|
|
379
|
+
act(() => {
|
|
380
|
+
resync = harness.current().refreshDomEditSelectionFromPreview(headline);
|
|
381
|
+
});
|
|
382
|
+
act(() => harness.current().applyDomSelection(null, { revealPanel: false }));
|
|
383
|
+
|
|
384
|
+
await act(() => resync);
|
|
385
|
+
|
|
386
|
+
expect(harness.current().domEditSelection).toBeNull();
|
|
387
|
+
harness.cleanup();
|
|
388
|
+
});
|
|
389
|
+
});
|
|
390
|
+
|
|
329
391
|
it("clears a committed selection when the active composition path changes", () => {
|
|
330
392
|
const { selection, harness } = setupSelectedHarness();
|
|
331
393
|
expect(harness.current().domEditSelection).toBe(selection);
|
|
@@ -356,8 +356,10 @@ export function useDomSelection({
|
|
|
356
356
|
|
|
357
357
|
const refreshDomEditSelectionFromPreview = useCallback(
|
|
358
358
|
// fallow-ignore-next-line complexity
|
|
359
|
-
async (selection: DomEditSelection) => {
|
|
360
|
-
const
|
|
359
|
+
async (selection: DomEditSelection, iframe = previewIframeRef.current) => {
|
|
360
|
+
const stillSelected = () =>
|
|
361
|
+
domEditSelectionsTargetSame(domEditSelectionRef.current, selection);
|
|
362
|
+
if (!stillSelected()) return;
|
|
361
363
|
let doc: Document | null = null;
|
|
362
364
|
try {
|
|
363
365
|
doc = iframe?.contentDocument ?? null;
|
|
@@ -384,7 +386,7 @@ export function useDomSelection({
|
|
|
384
386
|
}
|
|
385
387
|
|
|
386
388
|
const nextSelection = await buildDomSelectionFromTarget(element, { previous: selection });
|
|
387
|
-
if (nextSelection) {
|
|
389
|
+
if (nextSelection && stillSelected()) {
|
|
388
390
|
applyDomSelection(nextSelection, {
|
|
389
391
|
revealPanel: false,
|
|
390
392
|
preserveGroup: true,
|
|
@@ -547,7 +549,6 @@ export function useDomSelection({
|
|
|
547
549
|
buildDomSelectionForTimelineElement,
|
|
548
550
|
handleTimelineElementSelect,
|
|
549
551
|
refreshDomEditSelectionFromPreview,
|
|
550
|
-
refreshDomEditGroupSelectionsFromPreview,
|
|
551
552
|
applyMarqueeSelection,
|
|
552
553
|
};
|
|
553
554
|
}
|
|
@@ -89,7 +89,9 @@ export interface UseDomSelectionReturn {
|
|
|
89
89
|
element: TimelineElement,
|
|
90
90
|
) => Promise<DomEditSelection | null>;
|
|
91
91
|
handleTimelineElementSelect: (element: TimelineElement | null) => Promise<void>;
|
|
92
|
-
refreshDomEditSelectionFromPreview: (
|
|
93
|
-
|
|
92
|
+
refreshDomEditSelectionFromPreview: (
|
|
93
|
+
selection: DomEditSelection,
|
|
94
|
+
iframe?: HTMLIFrameElement | null,
|
|
95
|
+
) => Promise<void>;
|
|
94
96
|
applyMarqueeSelection: (selections: DomEditSelection[], additive: boolean) => DomSelectionResult;
|
|
95
97
|
}
|