@hyperframes/studio 0.8.104 → 0.8.105
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-DAoaajuM.js → hyperframes-player-tnfCiVdR.js} +1 -1
- package/dist/assets/{index-BDK4rTMb.js → index-Ca6LZlVb.js} +1 -1
- package/dist/assets/index-Cre9X4RS.css +1 -0
- package/dist/assets/{index-De2aO4XM.js → index-DEDhPmPD.js} +205 -205
- package/dist/assets/{index-WV9LroAD.js → index-zpe332hb.js} +1 -1
- package/dist/{chunk-62DDWOSH.js → chunk-EEXSYY5F.js} +19 -18
- package/dist/chunk-EEXSYY5F.js.map +1 -0
- package/dist/{chunk-6GAO75IU.js → chunk-NCUBAVGK.js} +10 -8
- package/dist/chunk-NCUBAVGK.js.map +1 -0
- package/dist/{chunk-HIGHVWYD.js → chunk-QADHJFDF.js} +2 -2
- package/dist/index.css +6 -1
- package/dist/index.css.map +1 -1
- package/dist/index.html +2 -2
- package/dist/index.js +614 -638
- package/dist/index.js.map +1 -1
- package/dist/player.js +2 -2
- package/dist/styles/tailwind-preset.js.map +1 -1
- package/dist/styles.css +1 -1
- package/dist/ui.js +2 -2
- package/package.json +8 -8
- package/src/captions/components/CaptionAnimationPanel.tsx +2 -2
- package/src/captions/components/CaptionPropertyPanel.tsx +2 -2
- package/src/captions/components/CaptionTimeline.tsx +3 -3
- package/src/components/AskAgentModal.tsx +1 -1
- package/src/components/LintModal.tsx +35 -35
- package/src/components/StudioErrorBoundary.tsx +1 -1
- package/src/components/StudioHeader.dom.test.tsx +4 -4
- package/src/components/StudioHeader.tsx +2 -1
- package/src/components/StudioToast.tsx +7 -16
- package/src/components/TimelineToolPicker.tsx +1 -1
- package/src/components/TimelineToolbar.tsx +11 -11
- package/src/components/dock/Dock.tsx +1 -1
- package/src/components/dock/dock.css +9 -1
- package/src/components/editor/AnimationCard.tsx +5 -5
- package/src/components/editor/AnimationCardParts.tsx +1 -1
- package/src/components/editor/BlockParamsPanel.tsx +3 -3
- package/src/components/editor/BorderRadiusEditor.tsx +8 -15
- package/src/components/editor/CanvasContextMenu.tsx +1 -1
- package/src/components/editor/ComputedTweenNotice.tsx +1 -1
- package/src/components/editor/DomEditRotateHandle.tsx +1 -1
- package/src/components/editor/EaseCurveSection.tsx +14 -19
- package/src/components/editor/EaseModeControls.tsx +2 -2
- package/src/components/editor/EaseParamFields.tsx +8 -8
- package/src/components/editor/FileTree.tsx +1 -1
- package/src/components/editor/FileTreeIcons.tsx +47 -26
- package/src/components/editor/FileTreeNodes.tsx +11 -8
- package/src/components/editor/GestureRecordControl.tsx +3 -3
- package/src/components/editor/GsapAddAnimationControl.tsx +1 -1
- package/src/components/editor/GsapAnimationSection.tsx +2 -2
- package/src/components/editor/InlineTextToolbar.tsx +4 -4
- package/src/components/editor/InspectorHeaderActions.tsx +1 -1
- package/src/components/editor/KeyframeDiamond.tsx +6 -4
- package/src/components/editor/KeyframeNavigation.tsx +4 -4
- package/src/components/editor/LayersPanel.tsx +3 -3
- package/src/components/editor/PromotableControl.tsx +2 -2
- package/src/components/editor/PropertyPanelEmptyState.tsx +4 -4
- package/src/components/editor/PropertyPanelFlatFooter.tsx +2 -2
- package/src/components/editor/PropertyPanelFlatHeader.test.tsx +1 -1
- package/src/components/editor/PropertyPanelFlatHeader.tsx +2 -2
- package/src/components/editor/SnapToolbar.tsx +5 -5
- package/src/components/editor/TimelineFxPopover.tsx +4 -4
- package/src/components/editor/Transform3DCube.tsx +1 -1
- package/src/components/editor/anchoredResizeReleaseShift.test.ts +0 -84
- package/src/components/editor/easeCurveSvg.tsx +1 -1
- package/src/components/editor/manualEditsDom.ts +3 -3
- package/src/components/editor/manualEditsDomPatches.test.ts +2 -86
- package/src/components/editor/manualEditsDomPatches.ts +0 -30
- package/src/components/editor/manualEditsSnapshot.ts +1 -0
- package/src/components/editor/persistSeam.integration.test.ts +0 -18
- package/src/components/editor/plainTranslate.ts +34 -3
- package/src/components/editor/propertyPanelColorCurveGraph.tsx +2 -2
- package/src/components/editor/propertyPanelColorGradingControls.tsx +1 -1
- package/src/components/editor/propertyPanelColorGradingSection.tsx +8 -8
- package/src/components/editor/propertyPanelColorGradingSlider.tsx +1 -1
- package/src/components/editor/propertyPanelColorSecondary.tsx +4 -4
- package/src/components/editor/propertyPanelFill.tsx +6 -6
- package/src/components/editor/propertyPanelFlatColorGradingAccessory.tsx +3 -3
- package/src/components/editor/propertyPanelFlatColorGradingSection.test.tsx +1 -1
- package/src/components/editor/propertyPanelFlatColorGradingSection.tsx +6 -9
- package/src/components/editor/propertyPanelFlatEffectsSection.tsx +4 -4
- package/src/components/editor/propertyPanelFlatMediaSection.tsx +2 -2
- package/src/components/editor/propertyPanelFlatMotionSection.tsx +2 -2
- package/src/components/editor/propertyPanelFlatOverlaysSection.tsx +2 -2
- package/src/components/editor/propertyPanelFlatPrimitives.test.tsx +4 -3
- package/src/components/editor/propertyPanelFlatPrimitives.tsx +1 -1
- package/src/components/editor/propertyPanelFlatSliderReadout.tsx +1 -1
- package/src/components/editor/propertyPanelFont.tsx +2 -2
- package/src/components/editor/propertyPanelFxCarveModule.tsx +1 -1
- package/src/components/editor/propertyPanelFxControls.tsx +2 -2
- package/src/components/editor/propertyPanelFxEqModule.tsx +2 -2
- package/src/components/editor/propertyPanelFxNodeRow.tsx +1 -1
- package/src/components/editor/propertyPanelFxPresetRun.tsx +1 -1
- package/src/components/editor/propertyPanelMediaSection.tsx +1 -1
- package/src/components/editor/propertyPanelPrimitives.tsx +1 -1
- package/src/components/editor/propertyPanelSections.tsx +2 -2
- package/src/components/editor/propertyPanelValueTier.test.ts +1 -1
- package/src/components/editor/propertyPanelValueTier.ts +1 -1
- package/src/components/feedback/StudioFeedbackCard.tsx +11 -23
- package/src/components/nle/AssetPreviewOverlay.tsx +1 -1
- package/src/components/nle/AudioMeterStrip.tsx +2 -2
- package/src/components/nle/NLEPreview.test.ts +8 -4
- package/src/components/nle/PreviewOverlays.tsx +1 -1
- package/src/components/nle/PreviewPane.tsx +3 -3
- package/src/components/nle/PreviewPoster.tsx +29 -1
- package/src/components/nle/PreviewZoomOverlay.tsx +1 -1
- package/src/components/panels/SlideshowPanel.tsx +4 -4
- package/src/components/panels/SlideshowSubPanels.tsx +19 -21
- package/src/components/panels/VariablesBindElement.tsx +1 -1
- package/src/components/panels/VariablesDeclarationForm.tsx +1 -1
- package/src/components/panels/VariablesPanel.tsx +4 -6
- package/src/components/panels/VariablesRowAction.tsx +1 -1
- package/src/components/renders/FfmpegRequiredNotice.tsx +4 -4
- package/src/components/renders/RenderQueue.tsx +2 -2
- package/src/components/renders/RenderQueueItem.tsx +3 -3
- package/src/components/sidebar/AssetCard.tsx +3 -3
- package/src/components/sidebar/AssetContextMenu.tsx +7 -7
- package/src/components/sidebar/AssetsTab.tsx +6 -6
- package/src/components/sidebar/AudioRow.tsx +5 -3
- package/src/components/sidebar/BlocksTab.tsx +6 -6
- package/src/components/sidebar/CompositionsTab.drag.test.tsx +3 -69
- package/src/components/sidebar/CompositionsTab.rootBadge.test.tsx +4 -50
- package/src/components/sidebar/CompositionsTab.thumbnails.test.tsx +256 -0
- package/src/components/sidebar/CompositionsTab.tsx +65 -12
- package/src/components/sidebar/PromptPreviewModal.tsx +3 -3
- package/src/components/sidebar/SidebarLintButton.tsx +3 -3
- package/src/components/sidebar/compositionsTabTestUtils.tsx +39 -0
- package/src/components/timelineToolbarStyles.ts +3 -3
- package/src/components/ui/Button.tsx +4 -4
- package/src/components/ui/HyperframesLogo.tsx +19 -18
- package/src/components/ui/Input.tsx +1 -1
- package/src/components/ui/Menu.tsx +4 -2
- package/src/hooks/elementOffsetStager.ts +8 -7
- package/src/hooks/useClipboard.source.test.ts +42 -4
- package/src/hooks/useClipboard.ts +13 -3
- package/src/hooks/useDomEditCommits.ts +0 -3
- package/src/hooks/useDomGeometryCommit.test.tsx +4 -1
- package/src/hooks/useDomGeometryCommit.ts +0 -1
- package/src/hooks/useDomGeometryCommits.test.tsx +177 -32
- package/src/hooks/useDomGeometryCommits.ts +4 -49
- package/src/player/components/ClipContextMenu.tsx +1 -1
- package/src/player/components/CompositionThumbnail.tsx +23 -11
- package/src/player/components/EditModal.tsx +6 -6
- package/src/player/components/KeyframeDiamondContextMenu.tsx +2 -2
- package/src/player/components/PlayerControls.tsx +3 -3
- package/src/player/components/ShortcutsPanel.tsx +8 -20
- package/src/player/components/TimelineCanvas.tsx +1 -1
- package/src/player/components/TimelineClip.tsx +2 -2
- package/src/player/components/TimelineEmptyState.tsx +2 -2
- package/src/player/components/TimelineLanes.tsx +0 -1
- package/src/player/components/TrackClipCount.tsx +1 -1
- package/src/player/components/VolumeControl.tsx +1 -1
- package/src/player/components/timelineClipChildren.tsx +1 -1
- package/src/player/components/timelineMotionStyles.test.ts +6 -22
- package/src/player/components/trackHeaderLabelRows.tsx +16 -16
- package/src/player/lib/thumbnailScheduler.ts +4 -5
- package/src/player/lib/timelineViewportBudgets.test.ts +1 -1
- package/src/player/lib/timelineViewportBudgets.ts +1 -1
- package/src/styles/hex-baseline.json +7 -19
- package/src/styles/studio.css +0 -9
- package/src/styles/tailwind-preset.shared.js +2 -1
- package/src/styles/theme.css +204 -147
- package/src/styles/theme.test.ts +13 -9
- package/src/utils/blockCategories.ts +41 -9
- package/src/utils/clipboardPayload.ts +2 -0
- package/dist/assets/index-CQN3M56N.css +0 -1
- package/dist/chunk-62DDWOSH.js.map +0 -1
- package/dist/chunk-6GAO75IU.js.map +0 -1
- package/src/hooks/gsapTargetCache.ts +0 -62
- /package/dist/{chunk-HIGHVWYD.js.map → chunk-QADHJFDF.js.map} +0 -0
|
@@ -4,7 +4,7 @@ import { ClipboardList, Film, Square, Type, X } from "../../icons/SystemIcons";
|
|
|
4
4
|
|
|
5
5
|
const ICON_BY_KIND = { text: Type, media: Film, other: Square } as const;
|
|
6
6
|
const ICON_COLOR_BY_KIND = {
|
|
7
|
-
text: "text-
|
|
7
|
+
text: "text-accent-ink",
|
|
8
8
|
media: "text-panel-media",
|
|
9
9
|
other: "text-panel-container",
|
|
10
10
|
} as const;
|
|
@@ -92,7 +92,7 @@ export function PropertyPanelFlatHeader({
|
|
|
92
92
|
track("button", "Copy element info");
|
|
93
93
|
onCopy();
|
|
94
94
|
}}
|
|
95
|
-
className={copied ? "text-
|
|
95
|
+
className={copied ? "text-accent-ink" : undefined}
|
|
96
96
|
>
|
|
97
97
|
<ClipboardList size={13} />
|
|
98
98
|
</button>
|
|
@@ -73,7 +73,7 @@ export const SnapToolbar = memo(function SnapToolbar() {
|
|
|
73
73
|
type="button"
|
|
74
74
|
className={`rounded-md p-1.5 transition-colors active:scale-[0.95] ${
|
|
75
75
|
motionPathArmed
|
|
76
|
-
? "bg-studio-accent/20 text-
|
|
76
|
+
? "bg-studio-accent/20 text-accent-ink"
|
|
77
77
|
: "bg-black/40 text-white/60 hover:bg-black/60 hover:text-white/80"
|
|
78
78
|
}`}
|
|
79
79
|
onClick={() => setMotionPathArmed(!motionPathArmed)}
|
|
@@ -99,7 +99,7 @@ export const SnapToolbar = memo(function SnapToolbar() {
|
|
|
99
99
|
type="button"
|
|
100
100
|
className={`rounded-md p-1.5 transition-colors active:scale-[0.95] ${
|
|
101
101
|
visible
|
|
102
|
-
? "bg-studio-accent/20 text-
|
|
102
|
+
? "bg-studio-accent/20 text-accent-ink"
|
|
103
103
|
: "bg-black/40 text-white/60 hover:bg-black/60 hover:text-white/80"
|
|
104
104
|
}`}
|
|
105
105
|
onClick={toggle}
|
|
@@ -115,7 +115,7 @@ export const SnapToolbar = memo(function SnapToolbar() {
|
|
|
115
115
|
type="button"
|
|
116
116
|
className={`rounded-md p-1.5 transition-colors active:scale-[0.95] ${
|
|
117
117
|
prefs.snapEnabled
|
|
118
|
-
? "bg-studio-accent/20 text-
|
|
118
|
+
? "bg-studio-accent/20 text-accent-ink"
|
|
119
119
|
: "bg-black/40 text-white/60 hover:bg-black/60 hover:text-white/80"
|
|
120
120
|
}`}
|
|
121
121
|
onClick={toggleSnap}
|
|
@@ -131,7 +131,7 @@ export const SnapToolbar = memo(function SnapToolbar() {
|
|
|
131
131
|
type="button"
|
|
132
132
|
className={`rounded-md p-1.5 transition-colors active:scale-[0.95] ${
|
|
133
133
|
prefs.gridVisible
|
|
134
|
-
? "bg-studio-accent/20 text-
|
|
134
|
+
? "bg-studio-accent/20 text-accent-ink"
|
|
135
135
|
: "bg-black/40 text-white/60 hover:bg-black/60 hover:text-white/80"
|
|
136
136
|
}`}
|
|
137
137
|
onClick={toggleGrid}
|
|
@@ -164,7 +164,7 @@ export const SnapToolbar = memo(function SnapToolbar() {
|
|
|
164
164
|
{gridPopoverOpen && (
|
|
165
165
|
<div
|
|
166
166
|
ref={popoverRef}
|
|
167
|
-
className="absolute right-0 top-full mt-1 rounded-lg bg-
|
|
167
|
+
className="absolute right-0 top-full mt-1 rounded-lg bg-raised border border-border p-3 shadow-xl min-w-[180px]"
|
|
168
168
|
>
|
|
169
169
|
<label className="flex items-center justify-between text-xs text-white/80 mb-2">
|
|
170
170
|
<span>Grid spacing</span>
|
|
@@ -139,7 +139,7 @@ export function TimelineFxPopover({
|
|
|
139
139
|
ref={rootRef}
|
|
140
140
|
role="dialog"
|
|
141
141
|
aria-label="Effects"
|
|
142
|
-
className="z-200 flex flex-col overflow-hidden rounded-md border border-
|
|
142
|
+
className="z-200 flex flex-col overflow-hidden rounded-md border border-border bg-raised p-2 shadow-xl"
|
|
143
143
|
style={clampedStyle(anchorRect)}
|
|
144
144
|
onKeyDown={onKeyDown}
|
|
145
145
|
onPointerDown={(event) => event.stopPropagation()}
|
|
@@ -165,10 +165,10 @@ export function TimelineFxPopover({
|
|
|
165
165
|
onAuditionTracked={(id) => trackPresetAuditioned(id, { trackKind })}
|
|
166
166
|
/>
|
|
167
167
|
</div>
|
|
168
|
-
<div className="mt-2 flex shrink-0 items-center justify-between border-t border-
|
|
168
|
+
<div className="mt-2 flex shrink-0 items-center justify-between border-t border-border pt-2 text-[10px] text-text-muted">
|
|
169
169
|
<button
|
|
170
170
|
type="button"
|
|
171
|
-
className="hover:text-
|
|
171
|
+
className="hover:text-text-0"
|
|
172
172
|
onClick={() => {
|
|
173
173
|
onClose();
|
|
174
174
|
onOpenRack();
|
|
@@ -178,7 +178,7 @@ export function TimelineFxPopover({
|
|
|
178
178
|
</button>
|
|
179
179
|
<button
|
|
180
180
|
type="button"
|
|
181
|
-
className="hover:text-
|
|
181
|
+
className="hover:text-text-0"
|
|
182
182
|
onClick={() => {
|
|
183
183
|
onClose();
|
|
184
184
|
onOpenRack();
|
|
@@ -314,7 +314,7 @@ export function Transform3DCube({
|
|
|
314
314
|
aria-label="Keyframe 3D transform"
|
|
315
315
|
aria-pressed={keyframed}
|
|
316
316
|
className={`absolute left-1.5 top-1.5 rounded p-0.5 hover:bg-neutral-800 ${
|
|
317
|
-
keyframed ? "text-
|
|
317
|
+
keyframed ? "text-accent-ink" : "text-neutral-500 hover:text-neutral-200"
|
|
318
318
|
}`}
|
|
319
319
|
>
|
|
320
320
|
<svg
|
|
@@ -1,12 +1,6 @@
|
|
|
1
1
|
// @vitest-environment jsdom
|
|
2
2
|
import { afterEach, describe, expect, it } from "vitest";
|
|
3
|
-
import { applyStudioBoxSize, applyStudioPathOffset, readStudioBoxSize } from "./manualEditsDom";
|
|
4
|
-
import { reapplyPositionEditsAfterSeek } from "./manualEditsSeekReapply";
|
|
5
|
-
import { buildBoxSizePatches, buildPathOffsetPatches } from "./manualEditsDomPatches";
|
|
6
|
-
import { createManualOffsetDragMember, applyManualOffsetDragCommit } from "./manualOffsetDrag";
|
|
7
3
|
import { computeNextResizeAnchor } from "./domEditResizeLocal";
|
|
8
|
-
import type { PatchOperation } from "../../utils/sourcePatcher";
|
|
9
|
-
import { splitTopLevelWhitespace } from "./manualEditsStyleHelpers";
|
|
10
4
|
|
|
11
5
|
/**
|
|
12
6
|
* Center-anchored corner resize (CapCut model): the element scales about its
|
|
@@ -38,40 +32,6 @@ afterEach(() => {
|
|
|
38
32
|
document.body.innerHTML = "";
|
|
39
33
|
});
|
|
40
34
|
|
|
41
|
-
/** Apply a built PatchOperation[] to a live element, mirroring sourcePatcher's
|
|
42
|
-
* inline-style / attribute application — i.e. what the persisted source carries
|
|
43
|
-
* when it is re-parsed into the DOM on the next preview load. */
|
|
44
|
-
function applyPatchesToElement(el: HTMLElement, ops: PatchOperation[]): void {
|
|
45
|
-
for (const op of ops) {
|
|
46
|
-
if (op.type === "inline-style") {
|
|
47
|
-
if (op.value === null) el.style.removeProperty(op.property);
|
|
48
|
-
else el.style.setProperty(op.property, op.value);
|
|
49
|
-
} else if (op.type === "attribute") {
|
|
50
|
-
if (op.value === null) el.removeAttribute(op.property);
|
|
51
|
-
else el.setAttribute(op.property, op.value);
|
|
52
|
-
}
|
|
53
|
-
}
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
/** Net translate applied to an element, resolving the studio offset var()
|
|
57
|
-
* expression to its px value so we compare the actually-rendered translation. */
|
|
58
|
-
function resolvedTranslatePx(el: HTMLElement): { x: number; y: number } {
|
|
59
|
-
const raw = el.style.getPropertyValue("translate").trim();
|
|
60
|
-
if (!raw || raw === "none") return { x: 0, y: 0 };
|
|
61
|
-
const vx = Number.parseFloat(el.style.getPropertyValue("--hf-studio-offset-x")) || 0;
|
|
62
|
-
const vy = Number.parseFloat(el.style.getPropertyValue("--hf-studio-offset-y")) || 0;
|
|
63
|
-
const parts = splitTopLevelWhitespace(raw);
|
|
64
|
-
const parseAxis = (part: string, varVal: number): number => {
|
|
65
|
-
if (part && part.includes("--hf-studio-offset")) return varVal;
|
|
66
|
-
const n = Number.parseFloat(part);
|
|
67
|
-
return Number.isFinite(n) ? n : 0;
|
|
68
|
-
};
|
|
69
|
-
return {
|
|
70
|
-
x: parseAxis(parts[0] ?? "", vx),
|
|
71
|
-
y: parseAxis(parts[1] ?? "", vy),
|
|
72
|
-
};
|
|
73
|
-
}
|
|
74
|
-
|
|
75
35
|
describe("center-anchored corner resize — no shift after release", () => {
|
|
76
36
|
it("the per-frame center anchor converges (does NOT oscillate) — the release-shift root cause", () => {
|
|
77
37
|
// Model the pointermove anchor loop that pins the element's CENTER. The physical
|
|
@@ -157,48 +117,4 @@ describe("center-anchored corner resize — no shift after release", () => {
|
|
|
157
117
|
}
|
|
158
118
|
}
|
|
159
119
|
});
|
|
160
|
-
|
|
161
|
-
it("net translate after persist+reload equals the committed anchor offset (non-GSAP)", () => {
|
|
162
|
-
// The committed offset flows through the real apply → persist → reload chain
|
|
163
|
-
// unchanged (this hop was proved clean; the shift is upstream in the anchor
|
|
164
|
-
// loop above, not in persistence).
|
|
165
|
-
const el = document.createElement("div");
|
|
166
|
-
el.style.setProperty("width", "200px");
|
|
167
|
-
el.style.setProperty("height", "100px");
|
|
168
|
-
document.body.appendChild(el);
|
|
169
|
-
|
|
170
|
-
const anchorDx = -30;
|
|
171
|
-
const anchorDy = -18;
|
|
172
|
-
const finalSize = { width: 240, height: 130 };
|
|
173
|
-
|
|
174
|
-
applyStudioBoxSize(el, finalSize);
|
|
175
|
-
const memberResult = createManualOffsetDragMember({
|
|
176
|
-
key: "k",
|
|
177
|
-
selection: { element: el } as never,
|
|
178
|
-
element: el,
|
|
179
|
-
rect: { left: 0, top: 0, width: 240, height: 130, editScaleX: 1, editScaleY: 1 },
|
|
180
|
-
});
|
|
181
|
-
expect(memberResult.ok).toBe(true);
|
|
182
|
-
if (!memberResult.ok) return;
|
|
183
|
-
|
|
184
|
-
const finalOffset = applyManualOffsetDragCommit(memberResult.member, anchorDx, anchorDy);
|
|
185
|
-
|
|
186
|
-
applyStudioBoxSize(el, finalSize);
|
|
187
|
-
const patches = buildBoxSizePatches(el);
|
|
188
|
-
applyStudioPathOffset(el, finalOffset);
|
|
189
|
-
patches.push(...buildPathOffsetPatches(el));
|
|
190
|
-
|
|
191
|
-
expect(resolvedTranslatePx(el)).toEqual({ x: anchorDx, y: anchorDy });
|
|
192
|
-
|
|
193
|
-
// Persist → fresh element re-parsed from source → reload re-stamp.
|
|
194
|
-
const reloaded = document.createElement("div");
|
|
195
|
-
reloaded.style.setProperty("width", "200px");
|
|
196
|
-
reloaded.style.setProperty("height", "100px");
|
|
197
|
-
document.body.appendChild(reloaded);
|
|
198
|
-
applyPatchesToElement(reloaded, patches);
|
|
199
|
-
reapplyPositionEditsAfterSeek(reloaded.ownerDocument);
|
|
200
|
-
|
|
201
|
-
expect(resolvedTranslatePx(reloaded)).toEqual({ x: anchorDx, y: anchorDy });
|
|
202
|
-
expect(readStudioBoxSize(reloaded)).toEqual(finalSize);
|
|
203
|
-
});
|
|
204
120
|
});
|
|
@@ -253,9 +253,9 @@ function stripGsapTranslateFromTransform(element: HTMLElement): void {
|
|
|
253
253
|
// — as the non-GSAP path does — composes ON TOP of GSAP's transform, and the
|
|
254
254
|
// subsequent strip/reapply math compounds into a runaway matrix that flings the
|
|
255
255
|
// element off-canvas. So for GSAP-animated elements we keep `translate: none`
|
|
256
|
-
// and push the offset straight into GSAP's x/y via gsap.set; the var() offset
|
|
257
|
-
//
|
|
258
|
-
//
|
|
256
|
+
// and push the offset straight into GSAP's x/y via gsap.set; the var() offset an
|
|
257
|
+
// older Studio saved stays in the file, and GSAP re-reads it at init on reload.
|
|
258
|
+
// Returns true when handled as GSAP (caller must skip the CSS path).
|
|
259
259
|
// fallow-ignore-next-line complexity
|
|
260
260
|
function applyStudioPathOffsetViaGsap(
|
|
261
261
|
element: HTMLElement,
|
|
@@ -42,7 +42,6 @@ import {
|
|
|
42
42
|
STUDIO_MOTION_ORIGINAL_VISIBILITY_ATTR,
|
|
43
43
|
} from "./studioMotionTypes";
|
|
44
44
|
import {
|
|
45
|
-
buildPathOffsetPatches,
|
|
46
45
|
buildClearPathOffsetPatches,
|
|
47
46
|
buildBoxSizePatches,
|
|
48
47
|
buildClearBoxSizePatches,
|
|
@@ -50,7 +49,7 @@ import {
|
|
|
50
49
|
buildMotionPatches,
|
|
51
50
|
buildClearMotionPatches,
|
|
52
51
|
} from "./manualEditsDomPatches";
|
|
53
|
-
import { applyStudioBoxSize
|
|
52
|
+
import { applyStudioBoxSize } from "./manualEditsDom";
|
|
54
53
|
|
|
55
54
|
/* ── helpers ── */
|
|
56
55
|
|
|
@@ -71,39 +70,7 @@ function assertClearCoversKeys(buildOps: PatchOperation[], clearOps: PatchOperat
|
|
|
71
70
|
|
|
72
71
|
/* ── Path offset ─────────────────────────────────────────────────────────── */
|
|
73
72
|
|
|
74
|
-
describe("
|
|
75
|
-
function populatedPathEl(): HTMLElement {
|
|
76
|
-
const e = div();
|
|
77
|
-
e.style.setProperty(STUDIO_OFFSET_X_PROP, "10px");
|
|
78
|
-
e.style.setProperty(STUDIO_OFFSET_Y_PROP, "20px");
|
|
79
|
-
e.style.setProperty("translate", "10px 20px");
|
|
80
|
-
e.setAttribute(STUDIO_ORIGINAL_TRANSLATE_ATTR, "5px 10px");
|
|
81
|
-
e.setAttribute(STUDIO_ORIGINAL_INLINE_TRANSLATE_ATTR, "3px");
|
|
82
|
-
e.style.setProperty("display", "flex");
|
|
83
|
-
e.setAttribute(STUDIO_ORIGINAL_TRANSFORM_DISPLAY_ATTR, "block");
|
|
84
|
-
return e;
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
it("populated: captures offset styles, attrs, display, and transform-display marker in declaration order", () => {
|
|
88
|
-
const ops = buildPathOffsetPatches(populatedPathEl());
|
|
89
|
-
expect(ops).toEqual([
|
|
90
|
-
{ type: "inline-style", property: STUDIO_OFFSET_X_PROP, value: "10px" },
|
|
91
|
-
{ type: "inline-style", property: STUDIO_OFFSET_Y_PROP, value: "20px" },
|
|
92
|
-
{ type: "inline-style", property: "translate", value: "10px 20px" },
|
|
93
|
-
{ type: "attribute", property: STUDIO_PATH_OFFSET_ATTR, value: "true" },
|
|
94
|
-
{ type: "attribute", property: STUDIO_ORIGINAL_TRANSLATE_ATTR, value: "5px 10px" },
|
|
95
|
-
{ type: "attribute", property: STUDIO_ORIGINAL_INLINE_TRANSLATE_ATTR, value: "3px" },
|
|
96
|
-
{ type: "inline-style", property: "display", value: "flex" },
|
|
97
|
-
{ type: "attribute", property: STUDIO_ORIGINAL_TRANSFORM_DISPLAY_ATTR, value: "block" },
|
|
98
|
-
]);
|
|
99
|
-
});
|
|
100
|
-
|
|
101
|
-
it("empty: bare element yields only the path-offset marker", () => {
|
|
102
|
-
expect(buildPathOffsetPatches(div())).toEqual([
|
|
103
|
-
{ type: "attribute", property: STUDIO_PATH_OFFSET_ATTR, value: "true" },
|
|
104
|
-
]);
|
|
105
|
-
});
|
|
106
|
-
|
|
73
|
+
describe("buildClearPathOffsetPatches", () => {
|
|
107
74
|
it("clear: restores translate from STUDIO_ORIGINAL_INLINE_TRANSLATE_ATTR and display from STUDIO_ORIGINAL_TRANSFORM_DISPLAY_ATTR", () => {
|
|
108
75
|
const e = div();
|
|
109
76
|
e.setAttribute(STUDIO_ORIGINAL_INLINE_TRANSLATE_ATTR, "5px");
|
|
@@ -127,11 +94,6 @@ describe("buildPathOffsetPatches / buildClearPathOffsetPatches", () => {
|
|
|
127
94
|
const ops = buildClearPathOffsetPatches(e);
|
|
128
95
|
expect(ops.find((o) => o.property === "translate")?.value).toBeNull();
|
|
129
96
|
});
|
|
130
|
-
|
|
131
|
-
it("build/clear symmetry: clear addresses every {type,property} key that build emits", () => {
|
|
132
|
-
const e = populatedPathEl();
|
|
133
|
-
assertClearCoversKeys(buildPathOffsetPatches(e), buildClearPathOffsetPatches(e));
|
|
134
|
-
});
|
|
135
97
|
});
|
|
136
98
|
|
|
137
99
|
/* ── Box size ────────────────────────────────────────────────────────────── */
|
|
@@ -286,52 +248,6 @@ describe("buildBoxSizePatches / buildClearBoxSizePatches", () => {
|
|
|
286
248
|
});
|
|
287
249
|
});
|
|
288
250
|
|
|
289
|
-
/* ── Combined box-size + path-offset (anchored-corner resize) ──────────────── */
|
|
290
|
-
|
|
291
|
-
describe("anchored-corner combined patch: [...buildBoxSizePatches, ...buildPathOffsetPatches]", () => {
|
|
292
|
-
// NW/NE/SW resize commits size AND anchor offset in ONE persist. The two
|
|
293
|
-
// builders read the same already-mutated element and are concatenated; this
|
|
294
|
-
// is only safe if their {type,property} keys are disjoint (no builder
|
|
295
|
-
// overwrites the other's op when the source patcher applies them in order).
|
|
296
|
-
it("concatenation of both builders emits disjoint {type,property} keys (no collision)", () => {
|
|
297
|
-
const e = div();
|
|
298
|
-
applyStudioBoxSize(e, { width: 300, height: 200 });
|
|
299
|
-
applyStudioPathOffset(e, { x: 10, y: 20 });
|
|
300
|
-
|
|
301
|
-
const combined = [...buildBoxSizePatches(e), ...buildPathOffsetPatches(e)];
|
|
302
|
-
const keys = combined.map(opKey);
|
|
303
|
-
expect(new Set(keys).size, `duplicate {type,property} key in combined patch: ${keys}`).toBe(
|
|
304
|
-
keys.length,
|
|
305
|
-
);
|
|
306
|
-
});
|
|
307
|
-
|
|
308
|
-
it("combined patch carries BOTH markers so a soft-reload re-hydrates size and offset together", () => {
|
|
309
|
-
const e = div();
|
|
310
|
-
applyStudioBoxSize(e, { width: 300, height: 200 });
|
|
311
|
-
applyStudioPathOffset(e, { x: 10, y: 20 });
|
|
312
|
-
|
|
313
|
-
const combined = [...buildBoxSizePatches(e), ...buildPathOffsetPatches(e)];
|
|
314
|
-
const has = (property: string) =>
|
|
315
|
-
combined.some((op) => op.type === "attribute" && op.property === property);
|
|
316
|
-
expect(has(STUDIO_BOX_SIZE_ATTR)).toBe(true);
|
|
317
|
-
expect(has(STUDIO_PATH_OFFSET_ATTR)).toBe(true);
|
|
318
|
-
});
|
|
319
|
-
|
|
320
|
-
it("order is size-first: every box-size op precedes every path-offset op", () => {
|
|
321
|
-
const e = div();
|
|
322
|
-
applyStudioBoxSize(e, { width: 300, height: 200 });
|
|
323
|
-
applyStudioPathOffset(e, { x: 10, y: 20 });
|
|
324
|
-
|
|
325
|
-
const boxKeys = new Set(buildBoxSizePatches(e).map(opKey));
|
|
326
|
-
const combined = [...buildBoxSizePatches(e), ...buildPathOffsetPatches(e)];
|
|
327
|
-
const lastBoxIdx = combined.reduce((acc, op, i) => (boxKeys.has(opKey(op)) ? i : acc), -1);
|
|
328
|
-
const firstOffsetIdx = combined.findIndex(
|
|
329
|
-
(op) => op.type === "attribute" && op.property === STUDIO_PATH_OFFSET_ATTR,
|
|
330
|
-
);
|
|
331
|
-
expect(firstOffsetIdx).toBeGreaterThan(lastBoxIdx);
|
|
332
|
-
});
|
|
333
|
-
});
|
|
334
|
-
|
|
335
251
|
/* ── Rotation ────────────────────────────────────────────────────────────── */
|
|
336
252
|
|
|
337
253
|
describe("buildClearRotationPatches", () => {
|
|
@@ -72,36 +72,6 @@ function appendTransformDisplayOps(element: HTMLElement, ops: PatchOperation[]):
|
|
|
72
72
|
|
|
73
73
|
/* ── Path offset patches ─────────────────────────────────────────── */
|
|
74
74
|
|
|
75
|
-
export function buildPathOffsetPatches(element: HTMLElement): PatchOperation[] {
|
|
76
|
-
const ops: PatchOperation[] = [];
|
|
77
|
-
collectInlineStyleOps(element, [STUDIO_OFFSET_X_PROP, STUDIO_OFFSET_Y_PROP], ops);
|
|
78
|
-
// When GSAP owns the element's transform, the live inline translate is kept
|
|
79
|
-
// at "none" (the offset lives in GSAP's cache — see applyStudioPathOffset).
|
|
80
|
-
// Persist the var() expression in that case, so a reload re-folds the offset.
|
|
81
|
-
const inlineTranslate = element.style.getPropertyValue("translate");
|
|
82
|
-
const hasOffsetVars =
|
|
83
|
-
element.style.getPropertyValue(STUDIO_OFFSET_X_PROP) ||
|
|
84
|
-
element.style.getPropertyValue(STUDIO_OFFSET_Y_PROP);
|
|
85
|
-
const translateValue =
|
|
86
|
-
inlineTranslate && inlineTranslate !== "none"
|
|
87
|
-
? inlineTranslate
|
|
88
|
-
: hasOffsetVars
|
|
89
|
-
? `var(${STUDIO_OFFSET_X_PROP}, 0px) var(${STUDIO_OFFSET_Y_PROP}, 0px)`
|
|
90
|
-
: null;
|
|
91
|
-
if (translateValue) {
|
|
92
|
-
ops.push({ type: "inline-style", property: "translate", value: translateValue });
|
|
93
|
-
}
|
|
94
|
-
ops.push({ type: "attribute", property: STUDIO_PATH_OFFSET_ATTR, value: "true" });
|
|
95
|
-
collectAttributeOps(
|
|
96
|
-
element,
|
|
97
|
-
[STUDIO_ORIGINAL_TRANSLATE_ATTR, STUDIO_ORIGINAL_INLINE_TRANSLATE_ATTR],
|
|
98
|
-
ops,
|
|
99
|
-
);
|
|
100
|
-
collectInlineStyleOps(element, ["display"], ops);
|
|
101
|
-
collectAttributeOps(element, [STUDIO_ORIGINAL_TRANSFORM_DISPLAY_ATTR], ops);
|
|
102
|
-
return ops;
|
|
103
|
-
}
|
|
104
|
-
|
|
105
75
|
export function buildClearPathOffsetPatches(element: HTMLElement): PatchOperation[] {
|
|
106
76
|
const originalInlineTranslate = element.getAttribute(STUDIO_ORIGINAL_INLINE_TRANSLATE_ATTR);
|
|
107
77
|
const ops: PatchOperation[] = [
|
|
@@ -265,6 +265,7 @@ function restoreOriginalTranslateProperty(element: HTMLElement): void {
|
|
|
265
265
|
export function clearStudioPathOffset(element: HTMLElement): void {
|
|
266
266
|
if (
|
|
267
267
|
element.hasAttribute(STUDIO_PATH_OFFSET_ATTR) ||
|
|
268
|
+
element.hasAttribute(STUDIO_ORIGINAL_INLINE_TRANSLATE_ATTR) ||
|
|
268
269
|
styleUsesStudioOffset(element.style.getPropertyValue("translate"))
|
|
269
270
|
) {
|
|
270
271
|
restoreOriginalTranslateProperty(element);
|
|
@@ -14,8 +14,6 @@ import {
|
|
|
14
14
|
buildDomEditStylePatchOperation,
|
|
15
15
|
buildDomEditTextPatchOperation,
|
|
16
16
|
} from "./domEditingLayers";
|
|
17
|
-
import { buildPathOffsetPatches } from "./manualEditsDomPatches";
|
|
18
|
-
import { STUDIO_OFFSET_X_PROP, STUDIO_PATH_OFFSET_ATTR } from "./manualEditsTypes";
|
|
19
17
|
import { makeSelection } from "../../hooks/domSelectionTestHarness";
|
|
20
18
|
import { buildTextFieldChildOperations } from "../../hooks/domEditTextFieldCommitOps";
|
|
21
19
|
|
|
@@ -126,22 +124,6 @@ describe("persist seam source mutation", () => {
|
|
|
126
124
|
expect(findByHfId(html, "qa-image").getAttribute("style")).toContain("opacity: 0.4");
|
|
127
125
|
});
|
|
128
126
|
|
|
129
|
-
it("persists detached jsdom path offset operations", () => {
|
|
130
|
-
const element = document.createElement("div");
|
|
131
|
-
element.style.setProperty(STUDIO_OFFSET_X_PROP, "24px");
|
|
132
|
-
|
|
133
|
-
const html = patchAndExpectChange(
|
|
134
|
-
indexHtml,
|
|
135
|
-
clientTarget({ id: "qa-shape", hfId: "qa-shape", tagName: "div" }),
|
|
136
|
-
buildPathOffsetPatches(element),
|
|
137
|
-
);
|
|
138
|
-
const shape = findByHfId(html, "qa-shape");
|
|
139
|
-
|
|
140
|
-
expect(shape.getAttribute("style")).toContain(`${STUDIO_OFFSET_X_PROP}: 24px`);
|
|
141
|
-
expect(shape.getAttribute("style")).toContain("translate: var(--hf-studio-offset-x, 0px)");
|
|
142
|
-
expect(shape.getAttribute(STUDIO_PATH_OFFSET_ATTR)).toBe("true");
|
|
143
|
-
});
|
|
144
|
-
|
|
145
127
|
it("persists timeline data-start attribute operation", () => {
|
|
146
128
|
const html = patchAndExpectChange(
|
|
147
129
|
indexHtml,
|
|
@@ -1,8 +1,14 @@
|
|
|
1
1
|
import { roundTo3 } from "../../utils/rounding";
|
|
2
2
|
import { gsapWritesPosition, gsapWritesRotation } from "../../hooks/gsapRuntimeKeyframes";
|
|
3
3
|
import { readCssRotation } from "../../hooks/draggedGsapPosition";
|
|
4
|
-
import { readStudioPathOffset, readStudioRotation } from "./manualEditsDom";
|
|
4
|
+
import { readStudioPathOffset, readStudioRotation, styleUsesStudioOffset } from "./manualEditsDom";
|
|
5
5
|
import { splitTopLevelWhitespace } from "./manualEditsStyleHelpers";
|
|
6
|
+
import {
|
|
7
|
+
STUDIO_OFFSET_X_PROP,
|
|
8
|
+
STUDIO_OFFSET_Y_PROP,
|
|
9
|
+
STUDIO_ORIGINAL_INLINE_TRANSLATE_ATTR,
|
|
10
|
+
STUDIO_PATH_OFFSET_ATTR,
|
|
11
|
+
} from "./manualEditsTypes";
|
|
6
12
|
import type { PatchOperation } from "../../utils/sourcePatcher";
|
|
7
13
|
|
|
8
14
|
type Point = { x: number; y: number };
|
|
@@ -102,11 +108,36 @@ function formatTranslatePx(p: Point): string {
|
|
|
102
108
|
return `${roundTo3(p.x)}px ${roundTo3(p.y)}px`;
|
|
103
109
|
}
|
|
104
110
|
|
|
105
|
-
|
|
106
|
-
|
|
111
|
+
const LEGACY_OFFSET_VARS = [STUDIO_OFFSET_X_PROP, STUDIO_OFFSET_Y_PROP];
|
|
112
|
+
|
|
113
|
+
/** Writes a move as the element's own translate; ends a legacy offset's vars and mark. */
|
|
114
|
+
export function writePlainMove(el: HTMLElement, p: Point): PatchOperation[] {
|
|
115
|
+
writeTranslatePx(el, p);
|
|
116
|
+
const patches: PatchOperation[] = [
|
|
117
|
+
{ type: "inline-style", property: "translate", value: formatTranslatePx(p) },
|
|
118
|
+
{
|
|
119
|
+
type: "attribute",
|
|
120
|
+
property: STUDIO_ORIGINAL_INLINE_TRANSLATE_ATTR,
|
|
121
|
+
value: el.getAttribute(STUDIO_ORIGINAL_INLINE_TRANSLATE_ATTR),
|
|
122
|
+
},
|
|
123
|
+
];
|
|
124
|
+
for (const prop of LEGACY_OFFSET_VARS.filter((v) => el.style.getPropertyValue(v))) {
|
|
125
|
+
el.style.removeProperty(prop);
|
|
126
|
+
patches.push({ type: "inline-style", property: prop, value: null });
|
|
127
|
+
}
|
|
128
|
+
if (el.hasAttribute(STUDIO_PATH_OFFSET_ATTR)) {
|
|
129
|
+
el.removeAttribute(STUDIO_PATH_OFFSET_ATTR);
|
|
130
|
+
patches.push({ type: "attribute", property: STUDIO_PATH_OFFSET_ATTR, value: null });
|
|
131
|
+
}
|
|
132
|
+
return patches;
|
|
107
133
|
}
|
|
108
134
|
|
|
135
|
+
/** The first write records the author's own translate ("" for none), which Reset puts back. */
|
|
109
136
|
export function writeTranslatePx(el: HTMLElement, p: Point): void {
|
|
137
|
+
if (!el.hasAttribute(STUDIO_ORIGINAL_INLINE_TRANSLATE_ATTR)) {
|
|
138
|
+
const own = el.style.getPropertyValue("translate");
|
|
139
|
+
el.setAttribute(STUDIO_ORIGINAL_INLINE_TRANSLATE_ATTR, styleUsesStudioOffset(own) ? "" : own);
|
|
140
|
+
}
|
|
110
141
|
el.style.setProperty("translate", formatTranslatePx(p));
|
|
111
142
|
}
|
|
112
143
|
|
|
@@ -477,7 +477,7 @@ export function CurveGraph({
|
|
|
477
477
|
onSettle();
|
|
478
478
|
}
|
|
479
479
|
}}
|
|
480
|
-
className="mx-auto aspect-square w-full max-w-[200px] touch-none rounded-sm border border-panel-border-input bg-
|
|
480
|
+
className="mx-auto aspect-square w-full max-w-[200px] touch-none rounded-sm scheme-dark border border-panel-border-input bg-bg-0 outline-hidden focus:ring-1 focus:ring-inset focus:ring-panel-accent"
|
|
481
481
|
>
|
|
482
482
|
<defs>
|
|
483
483
|
<linearGradient id={`hf-hue-axis-${tab.key}`}>
|
|
@@ -491,7 +491,7 @@ export function CurveGraph({
|
|
|
491
491
|
</linearGradient>
|
|
492
492
|
</defs>
|
|
493
493
|
{[0.25, 0.5, 0.75].map((ratio) => (
|
|
494
|
-
<g key={ratio}
|
|
494
|
+
<g key={ratio} className="stroke-text-0/10" strokeWidth="0.5">
|
|
495
495
|
<line
|
|
496
496
|
x1={GRAPH_PADDING}
|
|
497
497
|
y1={GRAPH_PADDING + ratio * (GRAPH_SIZE - GRAPH_PADDING * 2)}
|
|
@@ -14,11 +14,11 @@ import { useTrackDesignInput } from "../../contexts/DesignPanelInputContext";
|
|
|
14
14
|
function StatusPill({ status }: { status: RuntimeColorGradingStatus }) {
|
|
15
15
|
const dotClass =
|
|
16
16
|
status.state === "active"
|
|
17
|
-
? "bg-
|
|
17
|
+
? "bg-accent"
|
|
18
18
|
: status.state === "pending"
|
|
19
|
-
? "bg-
|
|
19
|
+
? "bg-warning-ink"
|
|
20
20
|
: status.state === "unavailable"
|
|
21
|
-
? "bg-
|
|
21
|
+
? "bg-danger-ink"
|
|
22
22
|
: "bg-panel-text-5";
|
|
23
23
|
return (
|
|
24
24
|
<div
|
|
@@ -44,18 +44,18 @@ function HdrMediaWarning({ metadata }: { metadata: MediaMetadata | null }) {
|
|
|
44
44
|
.join(" · ");
|
|
45
45
|
|
|
46
46
|
return (
|
|
47
|
-
<div className="mb-3 rounded-md border border-amber-500/30 bg-amber-500/10 px-3 py-2 text-[11px] leading-4 text-
|
|
47
|
+
<div className="mb-3 rounded-md border border-amber-500/30 bg-amber-500/10 px-3 py-2 text-[11px] leading-4 text-warning-ink">
|
|
48
48
|
<div className="mb-1 flex min-w-0 items-center justify-between gap-2">
|
|
49
49
|
<span className="font-semibold">{metadata.color.label} source</span>
|
|
50
|
-
<span className="rounded-sm bg-amber-
|
|
50
|
+
<span className="rounded-sm bg-amber-500/15 px-1.5 py-0.5 text-[9px] font-semibold uppercase tracking-wide text-warning-ink">
|
|
51
51
|
SDR preview
|
|
52
52
|
</span>
|
|
53
53
|
</div>
|
|
54
|
-
<p className="text-
|
|
54
|
+
<p className="text-text-2">
|
|
55
55
|
These controls use the current SDR shader preview path. Render may stay HDR-tagged, but this
|
|
56
56
|
is not true HDR color grading yet.
|
|
57
57
|
</p>
|
|
58
|
-
{details && <p className="mt-1 truncate text-[10px] text-
|
|
58
|
+
{details && <p className="mt-1 truncate text-[10px] text-text-muted">{details}</p>}
|
|
59
59
|
</div>
|
|
60
60
|
);
|
|
61
61
|
}
|
|
@@ -120,7 +120,7 @@ function HoldBeforeButton({
|
|
|
120
120
|
}}
|
|
121
121
|
className={`flex h-6 w-6 shrink-0 items-center justify-center rounded transition-colors ${
|
|
122
122
|
active
|
|
123
|
-
? "bg-studio-accent text-
|
|
123
|
+
? "bg-studio-accent text-on-accent"
|
|
124
124
|
: "text-panel-text-4 hover:bg-panel-hover hover:text-panel-text-1"
|
|
125
125
|
} disabled:cursor-not-allowed disabled:opacity-40`}
|
|
126
126
|
title="Hold to show original"
|
|
@@ -158,7 +158,7 @@ export function ColorGradingSliderControl({
|
|
|
158
158
|
settings.onClick();
|
|
159
159
|
}}
|
|
160
160
|
className={`relative flex h-5 w-5 shrink-0 items-center justify-center rounded transition-colors hover:bg-panel-hover hover:text-panel-text-1 disabled:cursor-not-allowed disabled:opacity-40 ${
|
|
161
|
-
settings.active ? "text-
|
|
161
|
+
settings.active ? "text-accent-ink" : "text-panel-text-5"
|
|
162
162
|
}`}
|
|
163
163
|
title={settings.label}
|
|
164
164
|
>
|
|
@@ -204,13 +204,13 @@ export function PropertyPanelColorSecondary({
|
|
|
204
204
|
setSampling(false);
|
|
205
205
|
}
|
|
206
206
|
}}
|
|
207
|
-
className="flex min-h-7 items-center gap-1.5 text-[10px] font-medium text-
|
|
207
|
+
className="flex min-h-7 items-center gap-1.5 text-[10px] font-medium text-accent-ink hover:text-accent-ink/80 disabled:opacity-50"
|
|
208
208
|
>
|
|
209
209
|
<Eyedropper size={12} />
|
|
210
210
|
{sampling ? "Capturing frame" : "Sample color from frame"}
|
|
211
211
|
</button>
|
|
212
212
|
{captureError && (
|
|
213
|
-
<p role="alert" className="text-[9px] leading-4 text-
|
|
213
|
+
<p role="alert" className="text-[9px] leading-4 text-danger-ink">
|
|
214
214
|
{captureError}
|
|
215
215
|
</p>
|
|
216
216
|
)}
|
|
@@ -221,7 +221,7 @@ export function PropertyPanelColorSecondary({
|
|
|
221
221
|
type="button"
|
|
222
222
|
aria-pressed={!showMatte}
|
|
223
223
|
onClick={() => setShowMatte(false)}
|
|
224
|
-
className={!showMatte ? "text-
|
|
224
|
+
className={!showMatte ? "text-accent-ink" : "text-panel-text-4"}
|
|
225
225
|
>
|
|
226
226
|
Source
|
|
227
227
|
</button>
|
|
@@ -229,7 +229,7 @@ export function PropertyPanelColorSecondary({
|
|
|
229
229
|
type="button"
|
|
230
230
|
aria-pressed={showMatte}
|
|
231
231
|
onClick={() => setShowMatte(true)}
|
|
232
|
-
className={showMatte ? "text-
|
|
232
|
+
className={showMatte ? "text-accent-ink" : "text-panel-text-4"}
|
|
233
233
|
>
|
|
234
234
|
Selection matte
|
|
235
235
|
</button>
|