@hyperframes/studio 0.8.103 → 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-DG795Hwu.js → hyperframes-player-tnfCiVdR.js} +1 -1
- package/dist/assets/{index-BiEtDkae.js → index-Ca6LZlVb.js} +1 -1
- package/dist/assets/index-Cre9X4RS.css +1 -0
- package/dist/assets/{index-BPJRf2X9.js → index-DEDhPmPD.js} +215 -215
- package/dist/assets/{index-DuCZ3pQw.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.d.ts +181 -168
- package/dist/index.html +2 -2
- package/dist/index.js +1018 -919
- 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/DomEditOverlay.tsx +5 -6
- 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/PropertyPanel.tsx +3 -3
- 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/anchoredResizeCommitFeedsOffset.test.ts +46 -6
- package/src/components/editor/anchoredResizeReleaseShift.test.ts +0 -84
- package/src/components/editor/domEditOverlayGestures.ts +13 -19
- package/src/components/editor/domEditOverlayStartGesture.test.ts +170 -13
- package/src/components/editor/domEditOverlayStartGesture.ts +15 -25
- package/src/components/editor/easeCurveSvg.tsx +1 -1
- package/src/components/editor/manualEdits.test.ts +3 -9
- package/src/components/editor/manualEdits.ts +0 -1
- package/src/components/editor/manualEditsDom.ts +3 -13
- package/src/components/editor/manualEditsDomPatches.test.ts +3 -131
- package/src/components/editor/manualEditsDomPatches.ts +1 -53
- package/src/components/editor/manualEditsSnapshot.ts +3 -0
- package/src/components/editor/manualEditsTypes.ts +2 -0
- package/src/components/editor/manualOffsetDrag.test.ts +41 -0
- package/src/components/editor/manualOffsetDrag.ts +6 -27
- package/src/components/editor/persistSeam.integration.test.ts +0 -18
- package/src/components/editor/plainTranslate.ts +42 -6
- 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/propertyPanelTransformCommit.test.ts +29 -0
- package/src/components/editor/propertyPanelTransformCommit.ts +8 -5
- package/src/components/editor/propertyPanelTypes.ts +1 -0
- package/src/components/editor/propertyPanelValueTier.test.ts +1 -1
- package/src/components/editor/propertyPanelValueTier.ts +1 -1
- package/src/components/editor/rotateInlineSave.test.ts +111 -0
- package/src/components/editor/rotationDraft.test.ts +111 -0
- package/src/components/editor/rotationDraft.ts +145 -0
- package/src/components/editor/useDomEditNudge.test.tsx +33 -0
- package/src/components/editor/useDomEditNudge.ts +6 -2
- package/src/components/editor/useDomEditOverlayGestures.ts +22 -24
- 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/draggedGsapPosition.ts +28 -0
- package/src/hooks/elementOffsetStager.ts +34 -13
- package/src/hooks/gsapRuntimeBridge.ts +5 -3
- package/src/hooks/gsapRuntimeKeyframes.ts +36 -2
- package/src/hooks/plainRotation.test.ts +122 -0
- package/src/hooks/plainRotation.ts +42 -0
- 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/useDomEditSession.ts +5 -5
- package/src/hooks/useDomGeometryCommit.test.tsx +79 -1
- package/src/hooks/useDomGeometryCommit.ts +16 -17
- package/src/hooks/useDomGeometryCommits.test.tsx +233 -33
- package/src/hooks/useDomGeometryCommits.ts +27 -80
- package/src/hooks/useGsapAwareEditing.test.tsx +194 -11
- package/src/hooks/useGsapAwareEditing.ts +43 -42
- package/src/hooks/useInlineTextEdit.test.tsx +33 -3
- package/src/hooks/useInlineTextEdit.ts +2 -2
- 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
package/dist/ui.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import {
|
|
2
2
|
HyperframesLogo
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-EEXSYY5F.js";
|
|
4
4
|
import {
|
|
5
5
|
Button,
|
|
6
6
|
ContextMenu,
|
|
@@ -30,7 +30,7 @@ import {
|
|
|
30
30
|
fieldBase,
|
|
31
31
|
fieldText,
|
|
32
32
|
popupSurface
|
|
33
|
-
} from "./chunk-
|
|
33
|
+
} from "./chunk-NCUBAVGK.js";
|
|
34
34
|
import "./chunk-PZ5AY32C.js";
|
|
35
35
|
export {
|
|
36
36
|
Button,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@hyperframes/studio",
|
|
3
|
-
"version": "0.8.
|
|
3
|
+
"version": "0.8.105",
|
|
4
4
|
"description": "",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -60,12 +60,12 @@
|
|
|
60
60
|
"dockview-react": "8.3.1",
|
|
61
61
|
"gsap": "^3.13.0",
|
|
62
62
|
"mediabunny": "^1.45.3",
|
|
63
|
-
"@hyperframes/
|
|
64
|
-
"@hyperframes/
|
|
65
|
-
"@hyperframes/
|
|
66
|
-
"@hyperframes/
|
|
67
|
-
"@hyperframes/
|
|
68
|
-
"@hyperframes/sdk": "0.8.
|
|
63
|
+
"@hyperframes/core": "0.8.105",
|
|
64
|
+
"@hyperframes/player": "0.8.105",
|
|
65
|
+
"@hyperframes/parsers": "0.8.105",
|
|
66
|
+
"@hyperframes/shader-transitions": "0.8.105",
|
|
67
|
+
"@hyperframes/studio-server": "0.8.105",
|
|
68
|
+
"@hyperframes/sdk": "0.8.105"
|
|
69
69
|
},
|
|
70
70
|
"devDependencies": {
|
|
71
71
|
"@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.105"
|
|
85
85
|
},
|
|
86
86
|
"peerDependencies": {
|
|
87
87
|
"react": "19",
|
|
@@ -250,7 +250,7 @@ export const CaptionAnimationPanel = memo(function CaptionAnimationPanel() {
|
|
|
250
250
|
<div className="flex flex-col h-full min-h-0">
|
|
251
251
|
{gated && (
|
|
252
252
|
<div className="shrink-0 mx-3 mt-2 px-2 py-1.5 rounded-sm border border-amber-500/30 bg-amber-500/10">
|
|
253
|
-
<p className="text-2xs text-
|
|
253
|
+
<p className="text-2xs text-warning-ink leading-snug">
|
|
254
254
|
Animation editing isn't applied to playback or saved yet, so these controls are
|
|
255
255
|
disabled.
|
|
256
256
|
</p>
|
|
@@ -292,7 +292,7 @@ export const CaptionAnimationPanel = memo(function CaptionAnimationPanel() {
|
|
|
292
292
|
onClick={handleApplyToAll}
|
|
293
293
|
disabled={gated}
|
|
294
294
|
title={gated ? "Disabled until animation editing is applied to playback" : undefined}
|
|
295
|
-
className="w-full py-1.5 rounded-sm border border-neutral-700 text-2xs text-neutral-300 hover:border-studio-accent/50 hover:text-
|
|
295
|
+
className="w-full py-1.5 rounded-sm border border-neutral-700 text-2xs text-neutral-300 hover:border-studio-accent/50 hover:text-accent-ink transition-colors disabled:opacity-40 disabled:cursor-not-allowed disabled:hover:border-neutral-700 disabled:hover:text-neutral-300"
|
|
296
296
|
>
|
|
297
297
|
Apply to all groups
|
|
298
298
|
</button>
|
|
@@ -227,7 +227,7 @@ export const CaptionPropertyPanel = memo(function CaptionPropertyPanel({
|
|
|
227
227
|
className={[
|
|
228
228
|
"flex-1 py-0.5 rounded-sm text-2xs font-medium transition-colors",
|
|
229
229
|
activeTab === "style"
|
|
230
|
-
? "bg-studio-accent/20 text-
|
|
230
|
+
? "bg-studio-accent/20 text-accent-ink border border-studio-accent/50"
|
|
231
231
|
: "text-neutral-500 border border-neutral-800 hover:text-neutral-300 hover:border-neutral-600",
|
|
232
232
|
].join(" ")}
|
|
233
233
|
>
|
|
@@ -241,7 +241,7 @@ export const CaptionPropertyPanel = memo(function CaptionPropertyPanel({
|
|
|
241
241
|
className={[
|
|
242
242
|
"flex-1 py-0.5 rounded-sm text-2xs font-medium transition-colors",
|
|
243
243
|
activeTab === "animation"
|
|
244
|
-
? "bg-studio-accent/20 text-
|
|
244
|
+
? "bg-studio-accent/20 text-accent-ink border border-studio-accent/50"
|
|
245
245
|
: "text-neutral-500 border border-neutral-800 hover:text-neutral-300 hover:border-neutral-600",
|
|
246
246
|
].join(" ")}
|
|
247
247
|
>
|
|
@@ -109,8 +109,8 @@ export const CaptionTimeline = memo(function CaptionTimeline({
|
|
|
109
109
|
tabIndex={0}
|
|
110
110
|
aria-label={`Caption word "${seg.text}"`}
|
|
111
111
|
aria-pressed={isSelected}
|
|
112
|
-
className={`absolute top-1 bottom-1 rounded flex items-center overflow-hidden cursor-pointer focus-visible:ring-1 focus-visible:ring-
|
|
113
|
-
isSelected ? " ring-1 ring-
|
|
112
|
+
className={`absolute top-1 bottom-1 rounded flex items-center overflow-hidden cursor-pointer focus-visible:ring-1 focus-visible:ring-text-0 outline-hidden${
|
|
113
|
+
isSelected ? " ring-1 ring-text-0/50 z-10" : ""
|
|
114
114
|
}`}
|
|
115
115
|
style={{
|
|
116
116
|
left,
|
|
@@ -135,7 +135,7 @@ export const CaptionTimeline = memo(function CaptionTimeline({
|
|
|
135
135
|
|
|
136
136
|
{/* Playhead — correlates blocks with the current frame */}
|
|
137
137
|
<div
|
|
138
|
-
className="absolute top-0 bottom-0 w-px bg-
|
|
138
|
+
className="absolute top-0 bottom-0 w-px bg-text-0/70 pointer-events-none z-20"
|
|
139
139
|
style={{ left: playheadLeft }}
|
|
140
140
|
aria-hidden="true"
|
|
141
141
|
/>
|
|
@@ -138,7 +138,7 @@ export function AskAgentModal({
|
|
|
138
138
|
{navigator.platform.includes("Mac") ? "⌘" : "Ctrl"}+Enter to copy
|
|
139
139
|
</span>
|
|
140
140
|
<button
|
|
141
|
-
className="px-4 py-1.5 rounded-lg bg-
|
|
141
|
+
className="px-4 py-1.5 rounded-lg bg-accent text-xs font-medium text-on-accent hover:bg-accent-hover disabled:opacity-40 disabled:cursor-not-allowed"
|
|
142
142
|
disabled={!value.trim()}
|
|
143
143
|
onClick={handleSubmit}
|
|
144
144
|
>
|
|
@@ -75,11 +75,11 @@ export function LintModal({
|
|
|
75
75
|
<div className="flex items-center gap-3">
|
|
76
76
|
{hasIssues ? (
|
|
77
77
|
<div className="w-8 h-8 rounded-full bg-red-500/10 flex items-center justify-center">
|
|
78
|
-
<WarningIcon size={18} className="text-
|
|
78
|
+
<WarningIcon size={18} className="text-danger-ink" weight="fill" />
|
|
79
79
|
</div>
|
|
80
80
|
) : (
|
|
81
81
|
<div className="w-8 h-8 rounded-full bg-studio-accent/10 flex items-center justify-center">
|
|
82
|
-
<CheckCircleIcon size={18} className="text-
|
|
82
|
+
<CheckCircleIcon size={18} className="text-accent-ink" weight="fill" />
|
|
83
83
|
</div>
|
|
84
84
|
)}
|
|
85
85
|
<div>
|
|
@@ -107,10 +107,10 @@ export function LintModal({
|
|
|
107
107
|
onClick={handleCopyToAgent}
|
|
108
108
|
className={`px-3 py-1 text-xs font-medium rounded-lg transition-colors active:scale-[0.98] ${
|
|
109
109
|
copied
|
|
110
|
-
? "bg-
|
|
110
|
+
? "bg-accent text-on-accent"
|
|
111
111
|
: copyFailed
|
|
112
|
-
? "bg-
|
|
113
|
-
: "bg-
|
|
112
|
+
? "bg-danger text-on-danger"
|
|
113
|
+
: "bg-accent hover:bg-accent-hover text-on-accent"
|
|
114
114
|
}`}
|
|
115
115
|
>
|
|
116
116
|
{copied
|
|
@@ -128,41 +128,41 @@ export function LintModal({
|
|
|
128
128
|
</div>
|
|
129
129
|
)}
|
|
130
130
|
{errors.map((f, i) => (
|
|
131
|
-
<
|
|
132
|
-
<div className="flex items-start gap-2">
|
|
133
|
-
<WarningIcon size={14} className="text-red-400 shrink-0 mt-0.5" weight="fill" />
|
|
134
|
-
<div className="min-w-0">
|
|
135
|
-
<p className="text-sm text-neutral-200">{f.message}</p>
|
|
136
|
-
{f.file && <p className="text-xs text-neutral-600 font-mono mt-0.5">{f.file}</p>}
|
|
137
|
-
{f.fixHint && (
|
|
138
|
-
<div className="flex items-start gap-1 mt-1.5">
|
|
139
|
-
<CaretRightIcon size={10} className="text-studio-accent shrink-0 mt-0.5" />
|
|
140
|
-
<p className="text-xs text-studio-accent">{f.fixHint}</p>
|
|
141
|
-
</div>
|
|
142
|
-
)}
|
|
143
|
-
</div>
|
|
144
|
-
</div>
|
|
145
|
-
</div>
|
|
131
|
+
<LintFindingRow key={`e-${i}`} finding={f} tone="error" />
|
|
146
132
|
))}
|
|
147
133
|
{warnings.map((f, i) => (
|
|
148
|
-
<
|
|
149
|
-
<div className="flex items-start gap-2">
|
|
150
|
-
<WarningIcon size={14} className="text-amber-400 shrink-0 mt-0.5" />
|
|
151
|
-
<div className="min-w-0">
|
|
152
|
-
<p className="text-sm text-neutral-300">{f.message}</p>
|
|
153
|
-
{f.file && <p className="text-xs text-neutral-600 font-mono mt-0.5">{f.file}</p>}
|
|
154
|
-
{f.fixHint && (
|
|
155
|
-
<div className="flex items-start gap-1 mt-1.5">
|
|
156
|
-
<CaretRightIcon size={10} className="text-studio-accent shrink-0 mt-0.5" />
|
|
157
|
-
<p className="text-xs text-studio-accent">{f.fixHint}</p>
|
|
158
|
-
</div>
|
|
159
|
-
)}
|
|
160
|
-
</div>
|
|
161
|
-
</div>
|
|
162
|
-
</div>
|
|
134
|
+
<LintFindingRow key={`w-${i}`} finding={f} tone="warning" />
|
|
163
135
|
))}
|
|
164
136
|
</div>
|
|
165
137
|
</div>
|
|
166
138
|
</div>
|
|
167
139
|
);
|
|
168
140
|
}
|
|
141
|
+
|
|
142
|
+
function LintFindingRow({ finding, tone }: { finding: LintFinding; tone: "error" | "warning" }) {
|
|
143
|
+
return (
|
|
144
|
+
<div className="py-3 border-b border-border last:border-0">
|
|
145
|
+
<div className="flex items-start gap-2">
|
|
146
|
+
<WarningIcon
|
|
147
|
+
size={14}
|
|
148
|
+
className={`${tone === "error" ? "text-danger-ink" : "text-warning-ink"} shrink-0 mt-0.5`}
|
|
149
|
+
weight={tone === "error" ? "fill" : undefined}
|
|
150
|
+
/>
|
|
151
|
+
<div className="min-w-0">
|
|
152
|
+
<p className={`text-sm ${tone === "error" ? "text-text-0" : "text-text-2"}`}>
|
|
153
|
+
{finding.message}
|
|
154
|
+
</p>
|
|
155
|
+
{finding.file && (
|
|
156
|
+
<p className="text-xs text-text-muted font-mono mt-0.5">{finding.file}</p>
|
|
157
|
+
)}
|
|
158
|
+
{finding.fixHint && (
|
|
159
|
+
<div className="flex items-start gap-1 mt-1.5">
|
|
160
|
+
<CaretRightIcon size={10} className="text-accent-ink shrink-0 mt-0.5" />
|
|
161
|
+
<p className="text-xs text-accent-ink">{finding.fixHint}</p>
|
|
162
|
+
</div>
|
|
163
|
+
)}
|
|
164
|
+
</div>
|
|
165
|
+
</div>
|
|
166
|
+
</div>
|
|
167
|
+
);
|
|
168
|
+
}
|
|
@@ -39,7 +39,7 @@ export class StudioErrorBoundary extends Component<Props, State> {
|
|
|
39
39
|
<div className="mt-2 flex items-center gap-2">
|
|
40
40
|
<button
|
|
41
41
|
onClick={() => this.setState({ error: null })}
|
|
42
|
-
className="rounded-md bg-
|
|
42
|
+
className="rounded-md bg-accent px-5 py-2 text-sm font-medium text-on-accent transition-colors hover:bg-accent-hover active:scale-[0.98]"
|
|
43
43
|
>
|
|
44
44
|
Try again
|
|
45
45
|
</button>
|
|
@@ -139,16 +139,16 @@ it("shows Inspector pressed and filled only when on", () => {
|
|
|
139
139
|
const host = mount({ inspectorButtonActive: true });
|
|
140
140
|
const on = query(host, '[aria-label="Inspector"]');
|
|
141
141
|
expect(on.getAttribute("aria-pressed")).toBe("true");
|
|
142
|
-
expect(hasToken(on.className, "text-accent")).toBe(true);
|
|
143
|
-
expect(hasToken(on.className, "bg-
|
|
142
|
+
expect(hasToken(on.className, "text-accent-ink")).toBe(true);
|
|
143
|
+
expect(hasToken(on.className, "bg-on")).toBe(true);
|
|
144
144
|
act(() => mounted?.root.unmount());
|
|
145
145
|
mounted?.host.remove();
|
|
146
146
|
mounted = null;
|
|
147
147
|
|
|
148
148
|
const off = query(mount(), '[aria-label="Inspector"]');
|
|
149
149
|
expect(off.getAttribute("aria-pressed")).toBe("false");
|
|
150
|
-
expect(hasToken(off.className, "text-accent")).toBe(false);
|
|
151
|
-
expect(hasToken(off.className, "bg-
|
|
150
|
+
expect(hasToken(off.className, "text-accent-ink")).toBe(false);
|
|
151
|
+
expect(hasToken(off.className, "bg-on")).toBe(false);
|
|
152
152
|
});
|
|
153
153
|
|
|
154
154
|
it("keeps Capture a real download link rather than a button", () => {
|
|
@@ -126,7 +126,8 @@ export function StudioHeader({
|
|
|
126
126
|
aria-pressed={inspectorButtonActive}
|
|
127
127
|
className={cn(
|
|
128
128
|
"h-full rounded-none",
|
|
129
|
-
inspectorButtonActive &&
|
|
129
|
+
inspectorButtonActive &&
|
|
130
|
+
"bg-on text-accent-ink enabled:hover:bg-on-hover enabled:hover:text-accent-ink",
|
|
130
131
|
)}
|
|
131
132
|
icon={<InspectorIcon size={16} />}
|
|
132
133
|
onClick={() => {
|
|
@@ -14,23 +14,10 @@ export function StudioToast({ message, tone, leaving, onDismiss }: StudioToastPr
|
|
|
14
14
|
className={`motion-reduce:animate-none ${leaving ? "hf-toast-exit" : "hf-toast-enter"}`}
|
|
15
15
|
>
|
|
16
16
|
<div
|
|
17
|
-
className=
|
|
18
|
-
style={{
|
|
19
|
-
background: isError
|
|
20
|
-
? "linear-gradient(135deg, rgba(127,29,29,0.55), rgba(80,10,10,0.45))"
|
|
21
|
-
: "linear-gradient(135deg, rgba(38,38,38,0.55), rgba(23,23,23,0.45))",
|
|
22
|
-
backdropFilter: "blur(16px) saturate(1.6)",
|
|
23
|
-
WebkitBackdropFilter: "blur(16px) saturate(1.6)",
|
|
24
|
-
border: `1px solid ${isError ? "rgba(239,68,68,0.18)" : "rgba(255,255,255,0.08)"}`,
|
|
25
|
-
boxShadow: [
|
|
26
|
-
"0 8px 32px rgba(0,0,0,0.35)",
|
|
27
|
-
`inset 0 1px 0 ${isError ? "rgba(239,68,68,0.12)" : "rgba(255,255,255,0.06)"}`,
|
|
28
|
-
`inset 0 -1px 0 rgba(0,0,0,0.15)`,
|
|
29
|
-
].join(", "),
|
|
30
|
-
}}
|
|
17
|
+
className={`relative flex max-w-[min(420px,calc(100vw-48px))] items-center gap-3 overflow-hidden rounded-2xl py-3 pl-4 pr-2 text-[12px] ${toastSurface(isError)}`}
|
|
31
18
|
>
|
|
32
19
|
<span
|
|
33
|
-
className={`min-w-0 wrap-break-word leading-5 ${isError ? "text-
|
|
20
|
+
className={`min-w-0 wrap-break-word leading-5 ${isError ? "text-danger-ink" : "text-text-0"}`}
|
|
34
21
|
>
|
|
35
22
|
{message}
|
|
36
23
|
</span>
|
|
@@ -38,7 +25,7 @@ export function StudioToast({ message, tone, leaving, onDismiss }: StudioToastPr
|
|
|
38
25
|
<button
|
|
39
26
|
type="button"
|
|
40
27
|
onClick={onDismiss}
|
|
41
|
-
className="flex h-5 w-5 shrink-0 items-center justify-center rounded-md text-neutral-500 transition-colors hover:bg-
|
|
28
|
+
className="flex h-5 w-5 shrink-0 items-center justify-center rounded-md text-neutral-500 transition-colors hover:bg-hover hover:text-neutral-300"
|
|
42
29
|
aria-label="Dismiss"
|
|
43
30
|
>
|
|
44
31
|
<svg
|
|
@@ -57,3 +44,7 @@ export function StudioToast({ message, tone, leaving, onDismiss }: StudioToastPr
|
|
|
57
44
|
</div>
|
|
58
45
|
);
|
|
59
46
|
}
|
|
47
|
+
|
|
48
|
+
export function toastSurface(isError: boolean): string {
|
|
49
|
+
return `border shadow-popover backdrop-blur-md ${isError ? "border-danger/40 bg-raised" : "border-border bg-raised/95"}`;
|
|
50
|
+
}
|
|
@@ -81,7 +81,7 @@ export function TimelineToolPicker({ showSelectAroundPlayhead = true }) {
|
|
|
81
81
|
shortcut={row.shortcut}
|
|
82
82
|
onClick={row.run}
|
|
83
83
|
data-active={row.active || undefined}
|
|
84
|
-
className={row.active ? "bg-
|
|
84
|
+
className={row.active ? "bg-press text-text-0" : undefined}
|
|
85
85
|
>
|
|
86
86
|
<span className="flex items-center gap-2">
|
|
87
87
|
{row.icon}
|
|
@@ -307,11 +307,11 @@ export function TimelineToolbar({
|
|
|
307
307
|
className={
|
|
308
308
|
!onToggleKeyframe
|
|
309
309
|
? flatDisabled
|
|
310
|
-
: `${flatBtn} active:scale-[0.98] hover:bg-
|
|
310
|
+
: `${flatBtn} active:scale-[0.98] hover:bg-hover ${
|
|
311
311
|
keyframeState === "active"
|
|
312
|
-
? "text-
|
|
312
|
+
? "text-accent-ink"
|
|
313
313
|
: keyframeState === "inactive"
|
|
314
|
-
? "text-neutral-400 hover:text-
|
|
314
|
+
? "text-neutral-400 hover:text-accent-ink"
|
|
315
315
|
: "text-neutral-600 hover:text-neutral-400"
|
|
316
316
|
}`
|
|
317
317
|
}
|
|
@@ -342,9 +342,9 @@ export function TimelineToolbar({
|
|
|
342
342
|
onClick={() => setAutoKeyframeEnabled(!autoKeyframeEnabled)}
|
|
343
343
|
aria-label="Auto-record manual edits as keyframes"
|
|
344
344
|
aria-pressed={autoKeyframeEnabled}
|
|
345
|
-
className={`${flatBtn} active:scale-[0.98] hover:bg-
|
|
345
|
+
className={`${flatBtn} active:scale-[0.98] hover:bg-hover ${
|
|
346
346
|
autoKeyframeEnabled
|
|
347
|
-
? "text-
|
|
347
|
+
? "text-danger-ink"
|
|
348
348
|
: "text-neutral-600 hover:text-neutral-400"
|
|
349
349
|
}`}
|
|
350
350
|
>
|
|
@@ -442,7 +442,7 @@ export function TimelineToolbar({
|
|
|
442
442
|
}}
|
|
443
443
|
className={
|
|
444
444
|
canAdd
|
|
445
|
-
? `${flatBtn} text-
|
|
445
|
+
? `${flatBtn} text-text-2 hover:bg-hover hover:text-accent-ink active:scale-[0.98]`
|
|
446
446
|
: flatDisabled
|
|
447
447
|
}
|
|
448
448
|
>
|
|
@@ -479,8 +479,8 @@ export function TimelineToolbar({
|
|
|
479
479
|
onClick={() => setThumbnailMode(thumbnailsVisible ? "hidden" : "adaptive")}
|
|
480
480
|
className={`h-7 px-2 rounded-md text-[11px] font-medium transition-colors ${
|
|
481
481
|
thumbnailsVisible
|
|
482
|
-
? "bg-studio-accent/10 text-
|
|
483
|
-
: "text-neutral-400 hover:bg-
|
|
482
|
+
? "bg-studio-accent/10 text-accent-ink"
|
|
483
|
+
: "text-neutral-400 hover:bg-hover hover:text-neutral-200"
|
|
484
484
|
}`}
|
|
485
485
|
>
|
|
486
486
|
<Image size={16} aria-hidden="true" />
|
|
@@ -494,8 +494,8 @@ export function TimelineToolbar({
|
|
|
494
494
|
aria-pressed={zoomMode === "fit"}
|
|
495
495
|
className={`h-7 px-2 rounded-md text-[11px] font-medium transition-colors ${
|
|
496
496
|
zoomMode === "fit"
|
|
497
|
-
? "bg-studio-accent/10 text-
|
|
498
|
-
: "text-neutral-400 hover:bg-
|
|
497
|
+
? "bg-studio-accent/10 text-accent-ink"
|
|
498
|
+
: "text-neutral-400 hover:bg-hover hover:text-neutral-200"
|
|
499
499
|
}`}
|
|
500
500
|
>
|
|
501
501
|
<ArrowsOutLineHorizontal size={16} aria-hidden="true" />
|
|
@@ -531,7 +531,7 @@ export function TimelineToolbar({
|
|
|
531
531
|
}}
|
|
532
532
|
// h-6 on the input is the 24x24 WCAG 2.2 (2.5.8) target: the visible
|
|
533
533
|
// track stays 2px and the thumb 10px, only the pointer box grows.
|
|
534
|
-
className="mx-1 h-6 w-[96px] cursor-pointer appearance-none bg-transparent [&::-webkit-slider-runnable-track]:h-[2px] [&::-webkit-slider-runnable-track]:rounded-full [&::-webkit-slider-runnable-track]:bg-neutral-700 [&::-webkit-slider-thumb]:appearance-none [&::-webkit-slider-thumb]:w-[10px] [&::-webkit-slider-thumb]:h-[10px] [&::-webkit-slider-thumb]:rounded-full [&::-webkit-slider-thumb]:bg-
|
|
534
|
+
className="mx-1 h-6 w-[96px] cursor-pointer appearance-none bg-transparent [&::-webkit-slider-runnable-track]:h-[2px] [&::-webkit-slider-runnable-track]:rounded-full [&::-webkit-slider-runnable-track]:bg-neutral-700 [&::-webkit-slider-thumb]:appearance-none [&::-webkit-slider-thumb]:w-[10px] [&::-webkit-slider-thumb]:h-[10px] [&::-webkit-slider-thumb]:rounded-full [&::-webkit-slider-thumb]:bg-text-0 [&::-webkit-slider-thumb]:-mt-1 [&::-webkit-slider-thumb]:shadow-[0_0_0_2px_#0a0a0a,0_1px_3px_rgba(0,0,0,0.5)] [&::-webkit-slider-thumb]:cursor-grab [&::-webkit-slider-thumb:active]:cursor-grabbing"
|
|
535
535
|
/>
|
|
536
536
|
<Tooltip label="Zoom in">
|
|
537
537
|
<button
|
|
@@ -301,7 +301,7 @@ function WindowMenu() {
|
|
|
301
301
|
onClick={() => togglePanel(id)}
|
|
302
302
|
className="flex w-full items-center gap-2 px-3 py-1.5 text-left text-[11px] text-neutral-300 hover:bg-neutral-800"
|
|
303
303
|
>
|
|
304
|
-
<span className="w-3 text-
|
|
304
|
+
<span className="w-3 text-accent-ink">{openPanels.has(id) ? "✓" : ""}</span>
|
|
305
305
|
{PANEL_DEFINITIONS[id].title}
|
|
306
306
|
</button>
|
|
307
307
|
))}
|
|
@@ -1,9 +1,17 @@
|
|
|
1
1
|
@import "dockview-react/dist/styles/dockview.css";
|
|
2
2
|
|
|
3
|
+
.dv-shell:has(.hf-dock) {
|
|
4
|
+
/* dockview's runtime stylesheet pins `color-scheme: dark` on its theme class, which sits on
|
|
5
|
+
* the shell around the dock. */
|
|
6
|
+
color-scheme: inherit;
|
|
7
|
+
}
|
|
8
|
+
|
|
3
9
|
.hf-dock {
|
|
4
10
|
--dv-group-view-background-color: var(--panel-card-bg);
|
|
5
11
|
--dv-tabs-and-actions-container-background-color: var(--panel-strip-bg);
|
|
6
12
|
--dv-tabs-and-actions-container-height: 36px;
|
|
13
|
+
--dv-icon-hover-background-color: var(--color-hover);
|
|
14
|
+
--dv-tabs-container-scrollbar-color: var(--color-text-muted);
|
|
7
15
|
/* The fill paints the shown tab, so every tab state is transparent. */
|
|
8
16
|
--dv-activegroup-visiblepanel-tab-background-color: transparent;
|
|
9
17
|
--dv-activegroup-hiddenpanel-tab-background-color: transparent;
|
|
@@ -178,7 +186,7 @@
|
|
|
178
186
|
}
|
|
179
187
|
|
|
180
188
|
.dv-groupview:hover .hf-dock-strip-actions {
|
|
181
|
-
opacity: 0.
|
|
189
|
+
opacity: 0.8;
|
|
182
190
|
}
|
|
183
191
|
|
|
184
192
|
.hf-dock-strip-actions:hover,
|
|
@@ -201,7 +201,7 @@ export const AnimationCard = memo(function AnimationCard({
|
|
|
201
201
|
className="flex w-full items-center gap-2 py-1.5 active:scale-[0.99]"
|
|
202
202
|
>
|
|
203
203
|
<span
|
|
204
|
-
className="rounded-sm bg-panel-accent/10 px-1.5 py-0.5 text-[10px] font-semibold text-
|
|
204
|
+
className="rounded-sm bg-panel-accent/10 px-1.5 py-0.5 text-[10px] font-semibold text-accent-ink"
|
|
205
205
|
title={METHOD_TOOLTIPS[animation.method]}
|
|
206
206
|
>
|
|
207
207
|
{methodLabel}
|
|
@@ -354,7 +354,7 @@ export const AnimationCard = memo(function AnimationCard({
|
|
|
354
354
|
|
|
355
355
|
{animation.method === "fromTo" && (
|
|
356
356
|
<div className="space-y-1">
|
|
357
|
-
<p className="text-[9px] font-semibold uppercase tracking-wider text-
|
|
357
|
+
<p className="text-[9px] font-semibold uppercase tracking-wider text-warning-ink">
|
|
358
358
|
From
|
|
359
359
|
</p>
|
|
360
360
|
<div className="space-y-1.5">
|
|
@@ -378,14 +378,14 @@ export const AnimationCard = memo(function AnimationCard({
|
|
|
378
378
|
onAdd={(prop) => onAddFromProperty?.(animation.id, prop)}
|
|
379
379
|
onOpen={() => setAddingFromProp(true)}
|
|
380
380
|
onClose={() => setAddingFromProp(false)}
|
|
381
|
-
buttonClassName="text-[11px] font-medium text-
|
|
381
|
+
buttonClassName="text-[11px] font-medium text-warning-ink transition-colors hover:text-text-0"
|
|
382
382
|
/>
|
|
383
383
|
</div>
|
|
384
384
|
</div>
|
|
385
385
|
)}
|
|
386
386
|
|
|
387
387
|
{animation.method === "fromTo" && Object.keys(animation.properties).length > 0 && (
|
|
388
|
-
<p className="text-[9px] font-semibold uppercase tracking-wider text-
|
|
388
|
+
<p className="text-[9px] font-semibold uppercase tracking-wider text-accent-ink">
|
|
389
389
|
To
|
|
390
390
|
</p>
|
|
391
391
|
)}
|
|
@@ -455,7 +455,7 @@ export const AnimationCard = memo(function AnimationCard({
|
|
|
455
455
|
<button
|
|
456
456
|
type="button"
|
|
457
457
|
onClick={() => onDeleteAnimation(animation.id)}
|
|
458
|
-
className="ml-auto text-[11px] font-medium text-
|
|
458
|
+
className="ml-auto text-[11px] font-medium rounded-sm text-danger-ink transition-colors hover:bg-danger/15"
|
|
459
459
|
title="Remove this animation"
|
|
460
460
|
>
|
|
461
461
|
Remove
|
|
@@ -46,7 +46,7 @@ function RemoveButton({ onClick, title }: { onClick: () => void; title: string }
|
|
|
46
46
|
<button
|
|
47
47
|
type="button"
|
|
48
48
|
onClick={onClick}
|
|
49
|
-
className="relative shrink-0 rounded-sm p-1.5 text-neutral-600 transition-colors hover:bg-neutral-800 hover:text-
|
|
49
|
+
className="relative shrink-0 rounded-sm p-1.5 text-neutral-600 transition-colors hover:bg-neutral-800 hover:text-danger-ink active:scale-[0.95]"
|
|
50
50
|
title={title}
|
|
51
51
|
aria-label={title}
|
|
52
52
|
>
|
|
@@ -170,7 +170,7 @@ export const BlockParamsPanel = memo(function BlockParamsPanel({
|
|
|
170
170
|
<div className="text-[10px] text-neutral-500">This block has no editable parameters.</div>
|
|
171
171
|
)}
|
|
172
172
|
{!fileManager && params.length > 0 && (
|
|
173
|
-
<div className="text-[10px] text-
|
|
173
|
+
<div className="text-[10px] text-warning-ink">
|
|
174
174
|
Block params can't be edited here — no project file access.
|
|
175
175
|
</div>
|
|
176
176
|
)}
|
|
@@ -189,12 +189,12 @@ export const BlockParamsPanel = memo(function BlockParamsPanel({
|
|
|
189
189
|
</div>
|
|
190
190
|
)}
|
|
191
191
|
{commitState.tone === "saved" && (
|
|
192
|
-
<div className="text-[10px] text-
|
|
192
|
+
<div className="text-[10px] text-accent-ink" role="status">
|
|
193
193
|
Saved to {compositionPath}
|
|
194
194
|
</div>
|
|
195
195
|
)}
|
|
196
196
|
{commitState.tone === "error" && (
|
|
197
|
-
<div className="text-[10px] text-
|
|
197
|
+
<div className="text-[10px] text-danger-ink" role="alert">
|
|
198
198
|
{commitState.message}
|
|
199
199
|
</div>
|
|
200
200
|
)}
|
|
@@ -63,6 +63,9 @@ export function BorderRadiusEditor({
|
|
|
63
63
|
}, [linked, uniform, tl, onCommit]);
|
|
64
64
|
|
|
65
65
|
const path = buildRoundedRectPath(PREVIEW_W, PREVIEW_H, sTL, sTR, sBR, sBL);
|
|
66
|
+
const dotFill = linked
|
|
67
|
+
? "fill-[light-dark(oklch(0.5_0.2_260),#3b82f6)]"
|
|
68
|
+
: "fill-[light-dark(oklch(0.55_0.2_294),#a78bfa)]";
|
|
66
69
|
|
|
67
70
|
return (
|
|
68
71
|
<div className="space-y-3">
|
|
@@ -73,21 +76,11 @@ export function BorderRadiusEditor({
|
|
|
73
76
|
viewBox={`0 0 ${PREVIEW_W} ${PREVIEW_H}`}
|
|
74
77
|
className="shrink-0"
|
|
75
78
|
>
|
|
76
|
-
<path
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
/>
|
|
82
|
-
<circle cx={sTL} cy={sTL} r={3} fill={linked ? "#3b82f6" : "#a78bfa"} />
|
|
83
|
-
<circle cx={PREVIEW_W - sTR} cy={sTR} r={3} fill={linked ? "#3b82f6" : "#a78bfa"} />
|
|
84
|
-
<circle
|
|
85
|
-
cx={PREVIEW_W - sBR}
|
|
86
|
-
cy={PREVIEW_H - sBR}
|
|
87
|
-
r={3}
|
|
88
|
-
fill={linked ? "#3b82f6" : "#a78bfa"}
|
|
89
|
-
/>
|
|
90
|
-
<circle cx={sBL} cy={PREVIEW_H - sBL} r={3} fill={linked ? "#3b82f6" : "#a78bfa"} />
|
|
79
|
+
<path d={path} className="fill-text-0/[0.06] stroke-text-0/25" strokeWidth={1.5} />
|
|
80
|
+
<circle cx={sTL} cy={sTL} r={3} className={dotFill} />
|
|
81
|
+
<circle cx={PREVIEW_W - sTR} cy={sTR} r={3} className={dotFill} />
|
|
82
|
+
<circle cx={PREVIEW_W - sBR} cy={PREVIEW_H - sBR} r={3} className={dotFill} />
|
|
83
|
+
<circle cx={sBL} cy={PREVIEW_H - sBL} r={3} className={dotFill} />
|
|
91
84
|
</svg>
|
|
92
85
|
|
|
93
86
|
<button
|
|
@@ -257,7 +257,7 @@ export const CanvasContextMenu = memo(function CanvasContextMenu({
|
|
|
257
257
|
{hasDelete && (
|
|
258
258
|
<button
|
|
259
259
|
type="button"
|
|
260
|
-
className="w-full flex items-center justify-between px-3 py-1.5 text-xs text-
|
|
260
|
+
className="w-full flex items-center justify-between px-3 py-1.5 text-xs text-danger-ink hover:bg-neutral-800 cursor-pointer text-left"
|
|
261
261
|
onPointerDown={(e) => {
|
|
262
262
|
if (e.button !== 0) return;
|
|
263
263
|
e.preventDefault();
|
|
@@ -29,7 +29,7 @@ export function ComputedTweenNotice({
|
|
|
29
29
|
<button
|
|
30
30
|
type="button"
|
|
31
31
|
onClick={onUnroll}
|
|
32
|
-
className="shrink-0 rounded-sm px-1.5 py-0.5 text-[9px] font-medium text-
|
|
32
|
+
className="shrink-0 rounded-sm px-1.5 py-0.5 text-[9px] font-medium text-accent-ink hover:bg-neutral-800"
|
|
33
33
|
title="Rewrite the helper/loop into explicit tweens so this keyframe edits directly"
|
|
34
34
|
>
|
|
35
35
|
Unroll to edit
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { RotationCommit } from "./rotationDraft";
|
|
1
2
|
import { memo, useEffect, useMemo, useRef, type RefObject } from "react";
|
|
2
3
|
import { type DomEditSelection } from "./domEditing";
|
|
3
4
|
import type { PreviewMouseDownOptions } from "../../hooks/usePreviewInteraction";
|
|
@@ -10,6 +11,7 @@ import {
|
|
|
10
11
|
type BlockedMoveState,
|
|
11
12
|
type DomEditGroupPathOffsetCommit,
|
|
12
13
|
type FocusableDomEditOverlay,
|
|
14
|
+
type MoveCommitOptions,
|
|
13
15
|
type GestureState,
|
|
14
16
|
type GroupGestureState,
|
|
15
17
|
focusDomEditOverlayElement,
|
|
@@ -45,7 +47,7 @@ export {
|
|
|
45
47
|
hasDomEditRotationChanged,
|
|
46
48
|
resolveDomEditRotationGesture,
|
|
47
49
|
} from "./domEditOverlayGestures";
|
|
48
|
-
export type { DomEditGroupPathOffsetCommit } from "./domEditOverlayGestures";
|
|
50
|
+
export type { DomEditGroupPathOffsetCommit, MoveCommitOptions } from "./domEditOverlayGestures";
|
|
49
51
|
|
|
50
52
|
export interface DomEditOverlayProps {
|
|
51
53
|
iframeRef: RefObject<HTMLIFrameElement | null>;
|
|
@@ -81,7 +83,7 @@ export interface DomEditOverlayProps {
|
|
|
81
83
|
onPathOffsetCommit: (
|
|
82
84
|
selection: DomEditSelection,
|
|
83
85
|
next: { x: number; y: number },
|
|
84
|
-
modifiers?:
|
|
86
|
+
modifiers?: MoveCommitOptions,
|
|
85
87
|
) => Promise<unknown> | void;
|
|
86
88
|
onGroupPathOffsetCommit: (updates: DomEditGroupPathOffsetCommit[]) => Promise<unknown> | void;
|
|
87
89
|
onBoxSizeCommit: (
|
|
@@ -90,10 +92,7 @@ export interface DomEditOverlayProps {
|
|
|
90
92
|
offset?: { x: number; y: number },
|
|
91
93
|
restore?: () => void,
|
|
92
94
|
) => Promise<unknown> | void;
|
|
93
|
-
onRotationCommit: (
|
|
94
|
-
selection: DomEditSelection,
|
|
95
|
-
next: { angle: number },
|
|
96
|
-
) => Promise<unknown> | void;
|
|
95
|
+
onRotationCommit: (selection: DomEditSelection, next: RotationCommit) => Promise<unknown> | void;
|
|
97
96
|
onStyleCommit?: (property: string, value: string) => Promise<unknown> | void;
|
|
98
97
|
recordingState?: GestureRecordingState;
|
|
99
98
|
onToggleRecording?: () => void;
|
|
@@ -38,7 +38,7 @@ export function DomEditRotateHandle({
|
|
|
38
38
|
aria-label="Rotate selection"
|
|
39
39
|
onPointerDown={onStartRotate}
|
|
40
40
|
>
|
|
41
|
-
<span className="pointer-events-none flex h-[18px] w-[18px] items-center justify-center rounded-full border border-studio-accent/70 bg-studio-surface text-
|
|
41
|
+
<span className="pointer-events-none flex h-[18px] w-[18px] items-center justify-center rounded-full border border-studio-accent/70 bg-studio-surface text-accent-ink shadow-[0_0_3px_rgba(0,0,0,0.45)]">
|
|
42
42
|
<svg
|
|
43
43
|
width="11"
|
|
44
44
|
height="11"
|