@hyperframes/studio 0.6.0-alpha.8 → 0.6.0
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-DjsVzYFP.js → hyperframes-player-DOFETgjy.js} +1 -1
- package/dist/assets/index-D1JDq7Gg.css +1 -0
- package/dist/assets/index-DUqUmaoH.js +117 -0
- package/dist/favicon.svg +14 -0
- package/dist/index.html +3 -2
- package/package.json +9 -9
- package/src/App.tsx +428 -4299
- package/src/components/AskAgentModal.tsx +120 -0
- package/src/components/StudioHeader.tsx +133 -0
- package/src/components/StudioLeftSidebar.tsx +125 -0
- package/src/components/StudioPreviewArea.tsx +163 -0
- package/src/components/StudioRightPanel.tsx +198 -0
- package/src/components/TimelineToolbar.tsx +89 -0
- package/src/components/editor/DomEditOverlay.tsx +15 -1
- package/src/components/editor/PropertyPanel.test.ts +0 -49
- package/src/components/editor/PropertyPanel.tsx +132 -2763
- package/src/components/editor/domEditing.ts +38 -5
- package/src/components/editor/manualEditingAvailability.test.ts +2 -2
- package/src/components/editor/manualEditingAvailability.ts +1 -1
- package/src/components/editor/manualEdits.ts +32 -0
- package/src/components/editor/propertyPanelColor.tsx +371 -0
- package/src/components/editor/propertyPanelFill.tsx +421 -0
- package/src/components/editor/propertyPanelFont.tsx +455 -0
- package/src/components/editor/propertyPanelHelpers.ts +401 -0
- package/src/components/editor/propertyPanelPrimitives.tsx +357 -0
- package/src/components/editor/propertyPanelSections.tsx +453 -0
- package/src/components/editor/propertyPanelStyleSections.tsx +411 -0
- package/src/components/nle/NLELayout.tsx +8 -11
- package/src/components/nle/NLEPreview.tsx +3 -0
- package/src/components/renders/RenderQueue.tsx +102 -31
- package/src/components/renders/useRenderQueue.ts +8 -2
- package/src/components/sidebar/LeftSidebar.tsx +186 -186
- package/src/contexts/DomEditContext.tsx +137 -0
- package/src/contexts/FileManagerContext.tsx +110 -0
- package/src/contexts/PanelLayoutContext.tsx +68 -0
- package/src/contexts/StudioContext.tsx +135 -0
- package/src/hooks/useAppHotkeys.ts +326 -0
- package/src/hooks/useAskAgentModal.ts +162 -0
- package/src/hooks/useCaptionDetection.ts +132 -0
- package/src/hooks/useCompositionDimensions.ts +25 -0
- package/src/hooks/useConsoleErrorCapture.ts +60 -0
- package/src/hooks/useDomEditCommits.ts +437 -0
- package/src/hooks/useDomEditSession.ts +342 -0
- package/src/hooks/useDomEditTextCommits.ts +330 -0
- package/src/hooks/useDomSelection.ts +398 -0
- package/src/hooks/useFileManager.ts +431 -0
- package/src/hooks/useFrameCapture.ts +77 -0
- package/src/hooks/useLintModal.ts +35 -0
- package/src/hooks/useManifestPersistence.ts +492 -0
- package/src/hooks/usePanelLayout.ts +68 -0
- package/src/hooks/usePreviewInteraction.ts +153 -0
- package/src/hooks/useRenderClipContent.ts +124 -0
- package/src/hooks/useTimelineEditing.ts +472 -0
- package/src/player/components/Player.tsx +35 -4
- package/src/player/components/Timeline.test.ts +0 -8
- package/src/player/components/Timeline.tsx +10 -103
- package/src/player/components/TimelineClip.tsx +9 -244
- package/src/player/hooks/useTimelinePlayer.ts +140 -103
- package/src/utils/domEditHelpers.ts +50 -0
- package/src/utils/studioFontHelpers.ts +83 -0
- package/src/utils/studioHelpers.ts +214 -0
- package/src/utils/studioPreviewHelpers.ts +185 -0
- package/src/utils/timelineDiscovery.ts +1 -1
- package/dist/assets/index-14zH9lqh.css +0 -1
- package/dist/assets/index-ClYcrksa.js +0 -108
- package/src/player/components/TimelineClip.test.ts +0 -92
|
@@ -0,0 +1,198 @@
|
|
|
1
|
+
import { PropertyPanel } from "./editor/PropertyPanel";
|
|
2
|
+
import { MotionPanel } from "./editor/MotionPanel";
|
|
3
|
+
import { CaptionPropertyPanel } from "../captions/components/CaptionPropertyPanel";
|
|
4
|
+
import { RenderQueue } from "./renders/RenderQueue";
|
|
5
|
+
import type { RenderJob } from "./renders/useRenderQueue";
|
|
6
|
+
import type { StudioGsapMotion } from "./editor/studioMotion";
|
|
7
|
+
import {
|
|
8
|
+
STUDIO_INSPECTOR_PANELS_ENABLED,
|
|
9
|
+
STUDIO_MOTION_PANEL_ENABLED,
|
|
10
|
+
} from "./editor/manualEditingAvailability";
|
|
11
|
+
import { useCallback } from "react";
|
|
12
|
+
import { resolveDomEditSelection, type DomEditLayerItem } from "./editor/domEditing";
|
|
13
|
+
import { useStudioContext } from "../contexts/StudioContext";
|
|
14
|
+
import { usePanelLayoutContext } from "../contexts/PanelLayoutContext";
|
|
15
|
+
import { useFileManagerContext } from "../contexts/FileManagerContext";
|
|
16
|
+
import { useDomEditContext } from "../contexts/DomEditContext";
|
|
17
|
+
|
|
18
|
+
export interface StudioRightPanelProps {
|
|
19
|
+
selectedStudioMotion: StudioGsapMotion | null;
|
|
20
|
+
designPanelActive: boolean;
|
|
21
|
+
motionPanelActive: boolean;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export function StudioRightPanel({
|
|
25
|
+
selectedStudioMotion,
|
|
26
|
+
designPanelActive,
|
|
27
|
+
motionPanelActive,
|
|
28
|
+
}: StudioRightPanelProps) {
|
|
29
|
+
const {
|
|
30
|
+
rightWidth,
|
|
31
|
+
rightPanelTab,
|
|
32
|
+
setRightPanelTab,
|
|
33
|
+
handlePanelResizeStart,
|
|
34
|
+
handlePanelResizeMove,
|
|
35
|
+
handlePanelResizeEnd,
|
|
36
|
+
} = usePanelLayoutContext();
|
|
37
|
+
|
|
38
|
+
const {
|
|
39
|
+
captionEditMode,
|
|
40
|
+
previewIframeRef,
|
|
41
|
+
projectId,
|
|
42
|
+
activeCompPath,
|
|
43
|
+
compositionDimensions,
|
|
44
|
+
waitForPendingDomEditSaves,
|
|
45
|
+
renderQueue,
|
|
46
|
+
} = useStudioContext();
|
|
47
|
+
|
|
48
|
+
const {
|
|
49
|
+
domEditSelection,
|
|
50
|
+
domEditGroupSelections,
|
|
51
|
+
copiedAgentPrompt,
|
|
52
|
+
clearDomSelection,
|
|
53
|
+
handleDomStyleCommit,
|
|
54
|
+
handleDomPathOffsetCommit,
|
|
55
|
+
handleDomBoxSizeCommit,
|
|
56
|
+
handleDomRotationCommit,
|
|
57
|
+
handleDomTextCommit,
|
|
58
|
+
handleDomTextFieldStyleCommit,
|
|
59
|
+
handleDomAddTextField,
|
|
60
|
+
handleDomRemoveTextField,
|
|
61
|
+
handleDomManualEditsReset,
|
|
62
|
+
handleAskAgent,
|
|
63
|
+
handleDomMotionCommit,
|
|
64
|
+
handleDomMotionClear,
|
|
65
|
+
applyDomSelection,
|
|
66
|
+
} = useDomEditContext();
|
|
67
|
+
|
|
68
|
+
const { assets, fontAssets, handleImportFiles, handleImportFonts } = useFileManagerContext();
|
|
69
|
+
|
|
70
|
+
const isMasterView = !activeCompPath || activeCompPath === "index.html";
|
|
71
|
+
const handleSelectLayer = useCallback(
|
|
72
|
+
(layer: DomEditLayerItem) => {
|
|
73
|
+
const selection = resolveDomEditSelection(layer.element, {
|
|
74
|
+
activeCompositionPath: activeCompPath,
|
|
75
|
+
isMasterView,
|
|
76
|
+
preferClipAncestor: false,
|
|
77
|
+
});
|
|
78
|
+
if (selection) applyDomSelection(selection);
|
|
79
|
+
},
|
|
80
|
+
[activeCompPath, isMasterView, applyDomSelection],
|
|
81
|
+
);
|
|
82
|
+
|
|
83
|
+
const renderJobs = renderQueue.jobs as RenderJob[];
|
|
84
|
+
|
|
85
|
+
return (
|
|
86
|
+
<>
|
|
87
|
+
<div
|
|
88
|
+
className="group w-2 flex-shrink-0 cursor-col-resize flex items-center justify-center"
|
|
89
|
+
style={{ touchAction: "none" }}
|
|
90
|
+
onPointerDown={(e) => handlePanelResizeStart("right", e)}
|
|
91
|
+
onPointerMove={handlePanelResizeMove}
|
|
92
|
+
onPointerUp={handlePanelResizeEnd}
|
|
93
|
+
>
|
|
94
|
+
<div className="h-[52px] w-px bg-white/12 transition-colors group-hover:bg-white/18 group-active:bg-white/24" />
|
|
95
|
+
</div>
|
|
96
|
+
<div
|
|
97
|
+
className="flex flex-col border-l border-neutral-800 bg-neutral-900 flex-shrink-0"
|
|
98
|
+
style={{ width: rightWidth }}
|
|
99
|
+
>
|
|
100
|
+
{captionEditMode ? (
|
|
101
|
+
<CaptionPropertyPanel iframeRef={previewIframeRef} />
|
|
102
|
+
) : (
|
|
103
|
+
<>
|
|
104
|
+
<div className="flex items-center gap-1 border-b border-neutral-800 px-3 py-2">
|
|
105
|
+
{STUDIO_INSPECTOR_PANELS_ENABLED && (
|
|
106
|
+
<>
|
|
107
|
+
<button
|
|
108
|
+
type="button"
|
|
109
|
+
onClick={() => setRightPanelTab("design")}
|
|
110
|
+
className={`h-8 rounded-xl px-3 text-[11px] font-medium transition-colors ${
|
|
111
|
+
rightPanelTab === "design"
|
|
112
|
+
? "bg-neutral-800 text-white"
|
|
113
|
+
: "text-neutral-500 hover:bg-neutral-800/70 hover:text-neutral-200"
|
|
114
|
+
}`}
|
|
115
|
+
>
|
|
116
|
+
Design
|
|
117
|
+
</button>
|
|
118
|
+
{STUDIO_MOTION_PANEL_ENABLED && (
|
|
119
|
+
<button
|
|
120
|
+
type="button"
|
|
121
|
+
onClick={() => setRightPanelTab("motion")}
|
|
122
|
+
className={`h-8 rounded-xl px-3 text-[11px] font-medium transition-colors ${
|
|
123
|
+
rightPanelTab === "motion"
|
|
124
|
+
? "bg-neutral-800 text-white"
|
|
125
|
+
: "text-neutral-500 hover:bg-neutral-800/70 hover:text-neutral-200"
|
|
126
|
+
}`}
|
|
127
|
+
>
|
|
128
|
+
Motion
|
|
129
|
+
</button>
|
|
130
|
+
)}
|
|
131
|
+
</>
|
|
132
|
+
)}
|
|
133
|
+
<button
|
|
134
|
+
type="button"
|
|
135
|
+
onClick={() => setRightPanelTab("renders")}
|
|
136
|
+
className={`h-8 rounded-xl px-3 text-[11px] font-medium transition-colors ${
|
|
137
|
+
rightPanelTab === "renders"
|
|
138
|
+
? "bg-neutral-800 text-white"
|
|
139
|
+
: "text-neutral-500 hover:bg-neutral-800/70 hover:text-neutral-200"
|
|
140
|
+
}`}
|
|
141
|
+
>
|
|
142
|
+
{renderJobs.length > 0 ? `Renders (${renderJobs.length})` : "Renders"}
|
|
143
|
+
</button>
|
|
144
|
+
</div>
|
|
145
|
+
<div className="min-h-0 flex-1">
|
|
146
|
+
{designPanelActive ? (
|
|
147
|
+
<PropertyPanel
|
|
148
|
+
projectId={projectId}
|
|
149
|
+
assets={assets}
|
|
150
|
+
element={domEditGroupSelections.length > 1 ? null : domEditSelection}
|
|
151
|
+
multiSelectCount={domEditGroupSelections.length}
|
|
152
|
+
copiedAgentPrompt={copiedAgentPrompt}
|
|
153
|
+
onClearSelection={clearDomSelection}
|
|
154
|
+
onSetStyle={handleDomStyleCommit}
|
|
155
|
+
onSetManualOffset={handleDomPathOffsetCommit}
|
|
156
|
+
onSetManualSize={handleDomBoxSizeCommit}
|
|
157
|
+
onSetManualRotation={handleDomRotationCommit}
|
|
158
|
+
onSetText={handleDomTextCommit}
|
|
159
|
+
onSetTextFieldStyle={handleDomTextFieldStyleCommit}
|
|
160
|
+
onAddTextField={handleDomAddTextField}
|
|
161
|
+
onRemoveTextField={handleDomRemoveTextField}
|
|
162
|
+
onResetManualEdits={handleDomManualEditsReset}
|
|
163
|
+
onAskAgent={handleAskAgent}
|
|
164
|
+
onImportAssets={handleImportFiles}
|
|
165
|
+
fontAssets={fontAssets}
|
|
166
|
+
onImportFonts={handleImportFonts}
|
|
167
|
+
activeCompositionPath={activeCompPath}
|
|
168
|
+
onSelectLayer={handleSelectLayer}
|
|
169
|
+
/>
|
|
170
|
+
) : motionPanelActive ? (
|
|
171
|
+
<MotionPanel
|
|
172
|
+
element={domEditGroupSelections.length > 1 ? null : domEditSelection}
|
|
173
|
+
motion={selectedStudioMotion}
|
|
174
|
+
onClearSelection={clearDomSelection}
|
|
175
|
+
onSetMotion={handleDomMotionCommit}
|
|
176
|
+
onClearMotion={handleDomMotionClear}
|
|
177
|
+
/>
|
|
178
|
+
) : (
|
|
179
|
+
<RenderQueue
|
|
180
|
+
jobs={renderJobs}
|
|
181
|
+
projectId={projectId}
|
|
182
|
+
onDelete={renderQueue.deleteRender}
|
|
183
|
+
onClearCompleted={renderQueue.clearCompleted}
|
|
184
|
+
onStartRender={async (format, quality, resolution, fps) => {
|
|
185
|
+
await waitForPendingDomEditSaves();
|
|
186
|
+
await renderQueue.startRender({ fps, quality, format, resolution });
|
|
187
|
+
}}
|
|
188
|
+
compositionDimensions={compositionDimensions}
|
|
189
|
+
isRendering={renderQueue.isRendering}
|
|
190
|
+
/>
|
|
191
|
+
)}
|
|
192
|
+
</div>
|
|
193
|
+
</>
|
|
194
|
+
)}
|
|
195
|
+
</div>
|
|
196
|
+
</>
|
|
197
|
+
);
|
|
198
|
+
}
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
import {
|
|
2
|
+
getNextTimelineZoomPercent,
|
|
3
|
+
getTimelineZoomPercent,
|
|
4
|
+
} from "../player/components/timelineZoom";
|
|
5
|
+
import { getTimelineToggleTitle } from "../utils/timelineDiscovery";
|
|
6
|
+
import { usePlayerStore } from "../player";
|
|
7
|
+
|
|
8
|
+
interface TimelineToolbarProps {
|
|
9
|
+
toggleTimelineVisibility: () => void;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export function TimelineToolbar({ toggleTimelineVisibility }: TimelineToolbarProps) {
|
|
13
|
+
const zoomMode = usePlayerStore((s) => s.zoomMode);
|
|
14
|
+
const manualZoomPercent = usePlayerStore((s) => s.manualZoomPercent);
|
|
15
|
+
const setZoomMode = usePlayerStore((s) => s.setZoomMode);
|
|
16
|
+
const setManualZoomPercent = usePlayerStore((s) => s.setManualZoomPercent);
|
|
17
|
+
const displayedTimelineZoomPercent = getTimelineZoomPercent(zoomMode, manualZoomPercent);
|
|
18
|
+
|
|
19
|
+
return (
|
|
20
|
+
<div className="border-b border-neutral-800/40 bg-neutral-950/96">
|
|
21
|
+
<div className="flex items-center justify-between px-3 py-2">
|
|
22
|
+
<div className="text-[10px] font-medium uppercase tracking-[0.16em] text-neutral-500">
|
|
23
|
+
Timeline
|
|
24
|
+
</div>
|
|
25
|
+
<div className="flex items-center gap-1">
|
|
26
|
+
<button
|
|
27
|
+
type="button"
|
|
28
|
+
onClick={() => setZoomMode("fit")}
|
|
29
|
+
className={`h-7 px-2.5 rounded-md border text-[11px] font-medium transition-colors ${
|
|
30
|
+
zoomMode === "fit"
|
|
31
|
+
? "border-studio-accent/30 bg-studio-accent/10 text-studio-accent"
|
|
32
|
+
: "border-neutral-800 text-neutral-400 hover:border-neutral-700 hover:text-neutral-200"
|
|
33
|
+
}`}
|
|
34
|
+
title="Fit timeline to width"
|
|
35
|
+
>
|
|
36
|
+
Fit
|
|
37
|
+
</button>
|
|
38
|
+
<button
|
|
39
|
+
type="button"
|
|
40
|
+
onClick={() => {
|
|
41
|
+
setZoomMode("manual");
|
|
42
|
+
setManualZoomPercent(getNextTimelineZoomPercent("out", zoomMode, manualZoomPercent));
|
|
43
|
+
}}
|
|
44
|
+
className="h-7 w-7 rounded-md border border-neutral-800 text-neutral-400 transition-colors hover:border-neutral-700 hover:text-neutral-200"
|
|
45
|
+
title="Zoom out"
|
|
46
|
+
>
|
|
47
|
+
-
|
|
48
|
+
</button>
|
|
49
|
+
<div className="min-w-[58px] text-center text-[10px] font-medium tabular-nums text-neutral-500">
|
|
50
|
+
{`${displayedTimelineZoomPercent}%`}
|
|
51
|
+
</div>
|
|
52
|
+
<button
|
|
53
|
+
type="button"
|
|
54
|
+
onClick={() => {
|
|
55
|
+
setZoomMode("manual");
|
|
56
|
+
setManualZoomPercent(getNextTimelineZoomPercent("in", zoomMode, manualZoomPercent));
|
|
57
|
+
}}
|
|
58
|
+
className="h-7 w-7 rounded-md border border-neutral-800 text-neutral-400 transition-colors hover:border-neutral-700 hover:text-neutral-200"
|
|
59
|
+
title="Zoom in"
|
|
60
|
+
>
|
|
61
|
+
+
|
|
62
|
+
</button>
|
|
63
|
+
<button
|
|
64
|
+
type="button"
|
|
65
|
+
onClick={toggleTimelineVisibility}
|
|
66
|
+
className="ml-1 flex h-7 w-7 items-center justify-center rounded-md text-neutral-500 transition-colors hover:bg-neutral-900 hover:text-neutral-200"
|
|
67
|
+
title={getTimelineToggleTitle(true)}
|
|
68
|
+
aria-label="Hide timeline editor"
|
|
69
|
+
>
|
|
70
|
+
<svg
|
|
71
|
+
width="14"
|
|
72
|
+
height="14"
|
|
73
|
+
viewBox="0 0 24 24"
|
|
74
|
+
fill="none"
|
|
75
|
+
stroke="currentColor"
|
|
76
|
+
strokeWidth="1.8"
|
|
77
|
+
strokeLinecap="round"
|
|
78
|
+
strokeLinejoin="round"
|
|
79
|
+
aria-hidden="true"
|
|
80
|
+
>
|
|
81
|
+
<path d="M5 7h14" />
|
|
82
|
+
<path d="m8 11 4 4 4-4" />
|
|
83
|
+
</svg>
|
|
84
|
+
</button>
|
|
85
|
+
</div>
|
|
86
|
+
</div>
|
|
87
|
+
</div>
|
|
88
|
+
);
|
|
89
|
+
}
|
|
@@ -85,6 +85,20 @@ interface DomEditOverlayProps {
|
|
|
85
85
|
onRotationCommit: (selection: DomEditSelection, next: { angle: number }) => Promise<void> | void;
|
|
86
86
|
}
|
|
87
87
|
|
|
88
|
+
function isElementVisibleForOverlay(el: HTMLElement): boolean {
|
|
89
|
+
const win = el.ownerDocument.defaultView;
|
|
90
|
+
if (!win) return true;
|
|
91
|
+
let current: HTMLElement | null = el;
|
|
92
|
+
while (current) {
|
|
93
|
+
const computed = win.getComputedStyle(current);
|
|
94
|
+
if (computed.display === "none" || computed.visibility === "hidden") return false;
|
|
95
|
+
const opacity = Number.parseFloat(computed.opacity);
|
|
96
|
+
if (Number.isFinite(opacity) && opacity <= 0.01) return false;
|
|
97
|
+
current = current.parentElement;
|
|
98
|
+
}
|
|
99
|
+
return true;
|
|
100
|
+
}
|
|
101
|
+
|
|
88
102
|
function toOverlayRect(
|
|
89
103
|
overlayEl: HTMLDivElement,
|
|
90
104
|
iframe: HTMLIFrameElement,
|
|
@@ -534,7 +548,7 @@ export const DomEditOverlay = memo(function DomEditOverlay({
|
|
|
534
548
|
|
|
535
549
|
if (sel) {
|
|
536
550
|
const el = resolveElement(doc, sel, resolvedElementRef);
|
|
537
|
-
if (el) {
|
|
551
|
+
if (el && isElementVisibleForOverlay(el)) {
|
|
538
552
|
setNextOverlayRect(toOverlayRect(overlayEl, iframe, el));
|
|
539
553
|
} else {
|
|
540
554
|
clearOverlayRect();
|
|
@@ -4,10 +4,8 @@ import {
|
|
|
4
4
|
buildStrokeWidthStyleUpdates,
|
|
5
5
|
getClipPathInsetPx,
|
|
6
6
|
getCssFilterFunctionPx,
|
|
7
|
-
getPropertyPanelVisibleSections,
|
|
8
7
|
inferBoxShadowPreset,
|
|
9
8
|
inferClipPathPreset,
|
|
10
|
-
isPropertyPanelMediaLikeSelection,
|
|
11
9
|
normalizePanelPxValue,
|
|
12
10
|
setCssFilterFunctionPx,
|
|
13
11
|
} from "./PropertyPanel";
|
|
@@ -66,51 +64,4 @@ describe("PropertyPanel style helpers", () => {
|
|
|
66
64
|
expect(buildStrokeStyleUpdates("none", "4px")).toEqual([["border-style", "none"]]);
|
|
67
65
|
expect(buildStrokeStyleUpdates("solid", "4px")).toEqual([["border-style", "solid"]]);
|
|
68
66
|
});
|
|
69
|
-
|
|
70
|
-
it("orders the simplified default inspector sections around high-confidence edits", () => {
|
|
71
|
-
expect(
|
|
72
|
-
getPropertyPanelVisibleSections({
|
|
73
|
-
hasSelection: true,
|
|
74
|
-
canEditStyles: true,
|
|
75
|
-
hasTextControls: true,
|
|
76
|
-
hasColorControls: true,
|
|
77
|
-
}),
|
|
78
|
-
).toEqual(["Text", "Layout", "Colors", "Radius", "Shadow"]);
|
|
79
|
-
|
|
80
|
-
expect(
|
|
81
|
-
getPropertyPanelVisibleSections({
|
|
82
|
-
hasSelection: true,
|
|
83
|
-
canEditStyles: true,
|
|
84
|
-
hasTextControls: false,
|
|
85
|
-
hasColorControls: false,
|
|
86
|
-
}),
|
|
87
|
-
).toEqual(["Layout", "Radius", "Shadow"]);
|
|
88
|
-
});
|
|
89
|
-
|
|
90
|
-
it("treats media tags and background-image layers as image-like controls", () => {
|
|
91
|
-
expect(
|
|
92
|
-
isPropertyPanelMediaLikeSelection({
|
|
93
|
-
tagName: "img",
|
|
94
|
-
styles: {},
|
|
95
|
-
}),
|
|
96
|
-
).toBe(true);
|
|
97
|
-
|
|
98
|
-
expect(
|
|
99
|
-
isPropertyPanelMediaLikeSelection({
|
|
100
|
-
tagName: "div",
|
|
101
|
-
styles: {
|
|
102
|
-
"background-image": "url(/assets/studio.png)",
|
|
103
|
-
},
|
|
104
|
-
}),
|
|
105
|
-
).toBe(true);
|
|
106
|
-
|
|
107
|
-
expect(
|
|
108
|
-
isPropertyPanelMediaLikeSelection({
|
|
109
|
-
tagName: "div",
|
|
110
|
-
styles: {
|
|
111
|
-
"background-image": "none",
|
|
112
|
-
},
|
|
113
|
-
}),
|
|
114
|
-
).toBe(false);
|
|
115
|
-
});
|
|
116
67
|
});
|