fix(studio): span the clip on the remaining duration-less tween paths

Two sibling call paths still answered from GSAP's 0.5s default while the
toggle path had moved to the clip-wide fallback.

isPlayheadWithinTween now takes the selection, so the toolbar stops
promising "extends animation" on a duration-less tween whose click actually
toggles an interior keyframe. The arc drag commit resolves its replacement
duration the same way its click-path sibling does, instead of authoring
duration 0.5 and collapsing the arc window.

The flat text section drops its two marker-clearing effects: the autofocus
marker is a ref now, read and cleared by the render that consumes it.
This commit is contained in:
Miguel Angel Simon Sierra
2026-07-28 00:13:46 +02:00
parent d57039882f
commit 62e866eda6
6 changed files with 50 additions and 20 deletions
@@ -1,4 +1,4 @@
import { useEffect, useState } from "react";
import { useEffect, useRef, useState } from "react";
import { useTrackDesignInput } from "../../contexts/DesignPanelInputContext";
import { Plus, X } from "../../icons/SystemIcons";
import { isTextEditableSelection, type DomEditSelection } from "./domEditing";
@@ -257,7 +257,10 @@ export function FlatTextSection({
const [activeFieldKey, setActiveFieldKey] = useState<string | null>(
element.textFields[0]?.key ?? null,
);
const [autoFocusFieldKey, setAutoFocusFieldKey] = useState<string | null>(null);
// Armed by the add handler, read and cleared by the render that first shows
// the new field. A ref rather than state: the marker only has to survive one
// render, and clearing it afterwards would be a state-syncing effect.
const autoFocusFieldKeyRef = useRef<string | null>(null);
useEffect(() => {
const nextFields = element.textFields;
@@ -267,21 +270,14 @@ export function FlatTextSection({
});
}, [element.id, element.selector, element.textFields]);
useEffect(() => {
setAutoFocusFieldKey(null);
}, [element.id, element.selector]);
useEffect(() => {
if (autoFocusFieldKey && autoFocusFieldKey === activeFieldKey) {
setAutoFocusFieldKey(null);
}
}, [activeFieldKey, autoFocusFieldKey]);
if (!isTextEditableSelection(element)) return null;
const textFields = element.textFields;
const activeField = textFields.find((field) => field.key === activeFieldKey) ?? textFields[0];
if (!activeField) return null;
const autoFocusActiveField = autoFocusFieldKeyRef.current === activeField.key;
if (autoFocusActiveField) autoFocusFieldKeyRef.current = null;
if (textFields.length > 1) {
return (
<div className="space-y-2.5">
@@ -290,13 +286,13 @@ export function FlatTextSection({
activeFieldKey={activeField.key}
styles={styles}
onSelect={(fieldKey) => {
setAutoFocusFieldKey(null);
autoFocusFieldKeyRef.current = null;
setActiveFieldKey(fieldKey);
}}
onAdd={() =>
void Promise.resolve(onAddTextField(activeField.key)).then((nextKey) => {
if (!nextKey) return;
setAutoFocusFieldKey(nextKey);
autoFocusFieldKeyRef.current = nextKey;
setActiveFieldKey(nextKey);
})
}
@@ -311,7 +307,7 @@ export function FlatTextSection({
onSetText={onSetText}
onSetTextFieldStyle={onSetTextFieldStyle}
onPreviewTextFieldStyle={onPreviewTextFieldStyle}
autoFocus={autoFocusFieldKey === activeField.key}
autoFocus={autoFocusActiveField}
/>
</div>
);
@@ -334,7 +330,7 @@ export function FlatTextSection({
track("button", "Add text field");
void Promise.resolve(onAddTextField(activeField.key)).then((nextKey) => {
if (!nextKey) return;
setAutoFocusFieldKey(nextKey);
autoFocusFieldKeyRef.current = nextKey;
setActiveFieldKey(nextKey);
});
}}