feat(ui): unify overlay animations and trim tooltip delays

Use base-ui's transition-status pattern (data-starting-style /
data-ending-style) for Dialog, DropdownMenu, Select, Tooltip and Popover
so open/close animate consistently at 150ms ease-out without flicker.
Wrap dialog popups in a centered flex container so the scale animation
no longer fights with translate-based positioning, and switch
PendingChangesBar to a real Popover so it actually animates closed.

Convert ScheduledTaskEditorDialog from raw Radix to the shared Dialog
wrapper, give ScheduledTasksDialog a stable min-height to prevent layout
shift mid-animation, and reset NewWorktreeDialog form state on open
instead of close so fields don't empty during the close transition.

Drop tooltip delay from 700ms to 300ms globally and remove all
per-component overrides except the model/variant/agent selectors in the
chat input (600ms).
This commit is contained in:
Bohdan Triapitsyn
2026-04-30 22:41:33 +03:00
parent 24533dfe32
commit 63da6e6292
57 changed files with 305 additions and 314 deletions
@@ -26,7 +26,7 @@ export const AIHighlightsBox: React.FC<AIHighlightsBoxProps> = ({
<div className="space-y-2 rounded-xl border border-border/60 bg-transparent px-3 py-2">
<div className="flex items-center justify-between gap-2">
<p className="typography-micro text-muted-foreground">{t('gitView.commit.aiHighlights.title')}</p>
<Tooltip delayDuration={1000}>
<Tooltip>
<TooltipTrigger asChild>
<Button
variant="ghost"
@@ -414,7 +414,7 @@ export const BranchIntegrationSection: React.FC<BranchIntegrationSectionProps> =
return (
<>
<Tooltip delayDuration={1000}>
<Tooltip>
<TooltipTrigger asChild>
<Button
variant="outline"
@@ -40,7 +40,6 @@ interface BranchSelectorProps {
onCreate: (name: string, remote?: GitRemote) => Promise<void>;
remotes?: GitRemote[];
disabled?: boolean;
tooltipDelayMs?: number;
}
const sanitizeBranchNameInput = (value: string): string => {
@@ -65,7 +64,6 @@ export const BranchSelector: React.FC<BranchSelectorProps> = ({
onCreate,
remotes = [],
disabled = false,
tooltipDelayMs = 1000,
}) => {
const { t } = useI18n();
const [isOpen, setIsOpen] = React.useState(false);
@@ -170,7 +168,7 @@ export const BranchSelector: React.FC<BranchSelectorProps> = ({
return (
<DropdownMenu open={isOpen} onOpenChange={setIsOpen}>
<Tooltip delayDuration={tooltipDelayMs}>
<Tooltip>
<TooltipTrigger asChild>
<DropdownMenuTrigger asChild>
<Button
@@ -150,7 +150,7 @@ export const ChangeRow = React.memo<ChangeRowProps>(function ChangeRow({
<span className="text-muted-foreground mx-0.5">/</span>
<span style={{ color: 'var(--status-error)' }}>-{deletions}</span>
</span>
<Tooltip delayDuration={200}>
<Tooltip>
<TooltipTrigger asChild>
<button
type="button"
@@ -104,7 +104,6 @@ interface IdentityDropdownProps {
identities: GitIdentityProfile[];
onSelect: (profile: GitIdentityProfile) => void;
isApplying: boolean;
tooltipDelayMs?: number;
iconOnly?: boolean;
}
@@ -113,7 +112,6 @@ const IdentityDropdown: React.FC<IdentityDropdownProps> = ({
identities,
onSelect,
isApplying,
tooltipDelayMs = 1000,
iconOnly = false,
}) => {
const { t } = useI18n();
@@ -121,7 +119,7 @@ const IdentityDropdown: React.FC<IdentityDropdownProps> = ({
return (
<DropdownMenu>
<Tooltip delayDuration={tooltipDelayMs}>
<Tooltip>
<TooltipTrigger asChild>
<DropdownMenuTrigger asChild>
<Button
@@ -224,7 +222,7 @@ export const GitHeader: React.FC<GitHeaderProps> = ({
const managementButtons = (
<div className="flex items-center gap-1 shrink-0">
{onOpenHistory ? (
<Tooltip delayDuration={useTwoRowHeader ? 300 : 1000}>
<Tooltip>
<TooltipTrigger asChild>
<Button
variant="ghost"
@@ -252,7 +250,7 @@ export const GitHeader: React.FC<GitHeaderProps> = ({
removingRemoteName={removingRemoteName}
disabled={!status}
iconOnly={true}
tooltipDelayMs={useTwoRowHeader ? 300 : 1000}
aheadCount={status.ahead}
behindCount={status.behind}
/>
@@ -264,7 +262,7 @@ export const GitHeader: React.FC<GitHeaderProps> = ({
identities={availableIdentities}
onSelect={onSelectIdentity}
isApplying={isApplyingIdentity}
tooltipDelayMs={useTwoRowHeader ? 300 : 1000}
iconOnly={false}
/>
);
@@ -287,7 +285,7 @@ export const GitHeader: React.FC<GitHeaderProps> = ({
onCheckout={onCheckoutBranch}
onCreate={onCreateBranch}
remotes={remotes}
tooltipDelayMs={useTwoRowHeader ? 300 : 1000}
/>
)}
</div>
@@ -88,7 +88,7 @@ export const HistoryCommitRow = React.memo(({
<code className="shrink-0 font-mono">
{entry.hash.slice(0, 8)}
</code>
<Tooltip delayDuration={500}>
<Tooltip>
<TooltipTrigger asChild>
<Button
variant="ghost"
@@ -1408,7 +1408,7 @@ export const PullRequestSection: React.FC<{
<div className="flex items-center justify-between gap-2">
<div className="flex items-center gap-2 min-w-0">
{pr ? (
<Tooltip delayDuration={300}>
<Tooltip>
<TooltipTrigger asChild>
<button
type="button"
@@ -1431,7 +1431,7 @@ export const PullRequestSection: React.FC<{
</div>
<div className="flex items-center gap-2">
{isLoading ? <RiLoader4Line className="size-4 animate-spin text-muted-foreground" /> : null}
<Tooltip delayDuration={300}>
<Tooltip>
<TooltipTrigger asChild>
<button
type="button"
@@ -1612,7 +1612,7 @@ export const PullRequestSection: React.FC<{
{pr.state === 'open' ? (
isEditingPr ? (
<>
<Tooltip delayDuration={300}>
<Tooltip>
<TooltipTrigger asChild>
<Button
variant="outline"
@@ -1631,7 +1631,7 @@ export const PullRequestSection: React.FC<{
</TooltipTrigger>
<TooltipContent><p>{t('gitView.pr.actions.cancelEditing')}</p></TooltipContent>
</Tooltip>
<Tooltip delayDuration={300}>
<Tooltip>
<TooltipTrigger asChild>
<Button
size="sm"
@@ -1647,7 +1647,7 @@ export const PullRequestSection: React.FC<{
</Tooltip>
</>
) : (
<Tooltip delayDuration={300}>
<Tooltip>
<TooltipTrigger asChild>
<Button
variant="outline"
@@ -1665,7 +1665,7 @@ export const PullRequestSection: React.FC<{
) : null}
{checks ? (
<Tooltip delayDuration={300}>
<Tooltip>
<TooltipTrigger asChild>
<Button
variant="outline"
@@ -1683,7 +1683,7 @@ export const PullRequestSection: React.FC<{
) : null}
{checks?.failure ? (
<Tooltip delayDuration={300}>
<Tooltip>
<TooltipTrigger asChild>
<Button
variant="outline"
@@ -1699,7 +1699,7 @@ export const PullRequestSection: React.FC<{
</Tooltip>
) : null}
<Tooltip delayDuration={300}>
<Tooltip>
<TooltipTrigger asChild>
<Button
variant="outline"
@@ -1714,7 +1714,7 @@ export const PullRequestSection: React.FC<{
<TooltipContent><p>{t('gitView.pr.actions.openComments')}</p></TooltipContent>
</Tooltip>
<Tooltip delayDuration={300}>
<Tooltip>
<TooltipTrigger asChild>
<Button
variant="outline"
@@ -1730,7 +1730,7 @@ export const PullRequestSection: React.FC<{
</Tooltip>
{canMerge && pr.draft && pr.state === 'open' ? (
<Tooltip delayDuration={300}>
<Tooltip>
<TooltipTrigger asChild>
<Button
variant="outline"
@@ -1765,7 +1765,7 @@ export const PullRequestSection: React.FC<{
<SelectItem value="rebase">{t('gitView.pr.mergeMethod.rebase')}</SelectItem>
</SelectContent>
</Select>
<Tooltip delayDuration={300}>
<Tooltip>
<TooltipTrigger asChild>
<Button
size="sm"
@@ -2064,7 +2064,7 @@ export const PullRequestSection: React.FC<{
{comment.authorLogin && comment.authorLogin !== comment.authorName ? ` · @${comment.authorLogin}` : ''}
</span>
{comment.createdAt ? <span className="whitespace-nowrap">{formatTimestamp(comment.createdAt)}</span> : null}
<Tooltip delayDuration={300}>
<Tooltip>
<TooltipTrigger asChild>
<Button
variant="ghost"
@@ -29,7 +29,6 @@ interface SyncActionsProps {
disabled: boolean;
removingRemoteName?: string | null;
iconOnly?: boolean;
tooltipDelayMs?: number;
aheadCount?: number;
behindCount?: number;
}
@@ -44,7 +43,6 @@ export const SyncActions: React.FC<SyncActionsProps> = ({
disabled,
removingRemoteName = null,
iconOnly = false,
tooltipDelayMs = 1000,
aheadCount = 0,
behindCount = 0,
}) => {
@@ -108,7 +106,7 @@ export const SyncActions: React.FC<SyncActionsProps> = ({
);
return (
<Tooltip delayDuration={tooltipDelayMs}>
<Tooltip>
<TooltipTrigger asChild>{button}</TooltipTrigger>
<TooltipContent sideOffset={8}>{tooltipText}</TooltipContent>
</Tooltip>
@@ -126,7 +124,7 @@ export const SyncActions: React.FC<SyncActionsProps> = ({
) => {
return (
<DropdownMenu>
<Tooltip delayDuration={tooltipDelayMs}>
<Tooltip>
<TooltipTrigger asChild>
<DropdownMenuTrigger asChild>
<Button