From c34e01c63eea9fb97d8d4e93546d884b0294e475 Mon Sep 17 00:00:00 2001 From: Maze Winther Date: Fri, 27 Mar 2026 21:24:59 +0100 Subject: refactor: clean up number formatting and step handling in property tabs --- .../editor/panels/properties/tabs/speed-tab.tsx | 57 ++++++++++++++-------- 1 file changed, 38 insertions(+), 19 deletions(-) (limited to 'apps/web/src/components/editor/panels/properties/tabs/speed-tab.tsx') diff --git a/apps/web/src/components/editor/panels/properties/tabs/speed-tab.tsx b/apps/web/src/components/editor/panels/properties/tabs/speed-tab.tsx index 4434890e..da86c626 100644 --- a/apps/web/src/components/editor/panels/properties/tabs/speed-tab.tsx +++ b/apps/web/src/components/editor/panels/properties/tabs/speed-tab.tsx @@ -22,16 +22,28 @@ import { SectionTitle, } from "@/components/section"; import { usePropertyDraft } from "../hooks/use-property-draft"; +import { + formatNumberForDisplay, + getFractionDigitsForStep, + snapToStep, +} from "@/utils/math"; + +const SPEED_STEP = 0.01; +const SPEED_FRACTION_DIGITS = getFractionDigitsForStep({ step: SPEED_STEP }); function rateToDisplay({ rate }: { rate: number }): string { - return rate.toFixed(2); + return formatNumberForDisplay({ + value: rate, + fractionDigits: SPEED_FRACTION_DIGITS, + }); } function parseSpeedInput({ input }: { input: string }): number | null { const parsed = parseFloat(input); if (Number.isNaN(parsed)) return null; - const rounded = Math.round(parsed * 100) / 100; - return clampRetimeRate({ rate: rounded }); + return clampRetimeRate({ + rate: snapToStep({ value: parsed, step: SPEED_STEP }), + }); } function buildRetime({ @@ -56,24 +68,21 @@ export function SpeedTab({ const rate = clampRetimeRate({ rate: element.retime?.rate ?? DEFAULT_RETIME_RATE, }); - const maintainPitchAvailable = canMaintainPitch({ rate }); + const isPitchPreserveAvailable = canMaintainPitch({ rate }); const maintainPitch = element.retime?.maintainPitch ?? false; const pendingRateRef = useRef(rate); - const applyRetime = ({ + const commitRetime = ({ rate: nextRate, maintainPitch: nextMaintainPitch, - pushHistory = true, }: { rate: number; maintainPitch: boolean; - pushHistory?: boolean; }) => { editor.timeline.updateElementRetime({ trackId, elementId: element.id, retime: buildRetime({ rate: nextRate, maintainPitch: nextMaintainPitch }), - pushHistory, }); }; @@ -82,10 +91,20 @@ export function SpeedTab({ parse: (input) => parseSpeedInput({ input }), onPreview: (nextRate) => { pendingRateRef.current = nextRate; - applyRetime({ rate: nextRate, maintainPitch, pushHistory: false }); + editor.timeline.previewElements({ + updates: [ + { + trackId, + elementId: element.id, + updates: { + retime: buildRetime({ rate: nextRate, maintainPitch }), + }, + }, + ], + }); }, onCommit: () => { - applyRetime({ rate: pendingRateRef.current, maintainPitch }); + commitRetime({ rate: pendingRateRef.current, maintainPitch }); }, }); @@ -115,20 +134,20 @@ export function SpeedTab({ onScrub={speedDraft.scrubTo} onScrubEnd={speedDraft.commitScrub} onReset={() => - applyRetime({ rate: DEFAULT_RETIME_RATE, maintainPitch }) + commitRetime({ rate: DEFAULT_RETIME_RATE, maintainPitch }) } isDefault={rate === DEFAULT_RETIME_RATE} />
- Change pitch - - applyRetime({ rate, maintainPitch: !checked }) - } - /> + Change pitch + + commitRetime({ rate, maintainPitch: !checked }) + } + />
-- cgit v1.3.1