From 63da6e62926756ef4c329e3aa3557d87d3fc4913 Mon Sep 17 00:00:00 2001 From: Bohdan Triapitsyn Date: Thu, 30 Apr 2026 22:41:33 +0300 Subject: [PATCH] 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). --- packages/ui/src/App.tsx | 8 +- packages/ui/src/components/chat/ChatInput.tsx | 4 +- .../ui/src/components/chat/FileAttachment.tsx | 2 +- .../ui/src/components/chat/ModelControls.tsx | 6 +- .../src/components/chat/PendingChangesBar.tsx | 89 +++++++++---------- packages/ui/src/components/chat/StatusRow.tsx | 4 +- .../ui/src/components/chat/TimelineDialog.tsx | 4 +- .../chat/TurnChangedFilesDropdown.tsx | 4 +- .../components/chat/changedFilesPopover.ts | 2 +- .../components/chat/message/MessageBody.tsx | 24 ++--- .../desktop/DesktopHostSwitcher.tsx | 6 +- packages/ui/src/components/layout/Header.tsx | 14 +-- .../layout/ProjectActionsButton.tsx | 4 +- .../ui/src/components/mcp/McpDropdown.tsx | 6 +- .../components/multirun/MultiRunLauncher.tsx | 6 +- .../components/sections/agents/AgentsPage.tsx | 6 +- .../GitIdentityEditorDialog.tsx | 8 +- .../magic-prompts/MagicPromptsPage.tsx | 4 +- .../sections/openchamber/GitHubSettings.tsx | 2 +- .../openchamber/KeyboardShortcutsSettings.tsx | 2 +- .../openchamber/NotificationSettings.tsx | 2 +- .../openchamber/OpenChamberVisualSettings.tsx | 10 +-- .../openchamber/OpenCodeCliSettings.tsx | 2 +- .../openchamber/SessionRetentionSettings.tsx | 2 +- .../sections/openchamber/TunnelSettings.tsx | 4 +- .../sections/openchamber/VoiceSettings.tsx | 4 +- .../openchamber/WorktreeSectionContent.tsx | 4 +- .../projects/ProjectActionsSection.tsx | 2 +- .../sections/providers/ProvidersPage.tsx | 4 +- .../remote-instances/RemoteInstancesPage.tsx | 2 +- .../components/sections/usage/UsagePage.tsx | 2 +- .../sections/usage/UsageSidebar.tsx | 2 +- .../components/session/BranchPickerDialog.tsx | 6 +- .../components/session/NewWorktreeDialog.tsx | 63 ++++++------- .../session/ScheduledTaskEditorDialog.tsx | 80 +++++++---------- .../session/ScheduledTasksDialog.tsx | 7 +- .../session/sidebar/sortableItems.tsx | 2 +- .../ui/src/components/ui/CommandPalette.tsx | 9 +- .../src/components/ui/ContextUsageDisplay.tsx | 2 +- .../ui/src/components/ui/MemoryDebugPanel.tsx | 2 +- packages/ui/src/components/ui/dialog.tsx | 27 +++--- .../ui/src/components/ui/dropdown-menu.tsx | 4 +- packages/ui/src/components/ui/select.tsx | 2 +- packages/ui/src/components/ui/tooltip.tsx | 2 +- .../src/components/views/MultiRunWindow.tsx | 67 ++++++++------ packages/ui/src/components/views/PlanView.tsx | 4 +- .../components/views/PreviewToggleButton.tsx | 2 +- .../ui/src/components/views/SettingsView.tsx | 4 +- .../src/components/views/SettingsWindow.tsx | 37 +++++--- .../components/views/git/AIHighlightsBox.tsx | 2 +- .../views/git/BranchIntegrationSection.tsx | 2 +- .../components/views/git/BranchSelector.tsx | 4 +- .../ui/src/components/views/git/ChangeRow.tsx | 2 +- .../ui/src/components/views/git/GitHeader.tsx | 12 ++- .../components/views/git/HistoryCommitRow.tsx | 2 +- .../views/git/PullRequestSection.tsx | 24 ++--- .../src/components/views/git/SyncActions.tsx | 6 +- 57 files changed, 305 insertions(+), 314 deletions(-) diff --git a/packages/ui/src/App.tsx b/packages/ui/src/App.tsx index 48ca7ef3..1d537d77 100644 --- a/packages/ui/src/App.tsx +++ b/packages/ui/src/App.tsx @@ -828,7 +828,7 @@ function App({ apis }: AppProps) { - +
@@ -873,7 +873,7 @@ function App({ apis }: AppProps) { - +
@@ -891,7 +891,7 @@ function App({ apis }: AppProps) { - +
@@ -916,7 +916,7 @@ function App({ apis }: AppProps) { - +
diff --git a/packages/ui/src/components/chat/ChatInput.tsx b/packages/ui/src/components/chat/ChatInput.tsx index 5e516297..014885d9 100644 --- a/packages/ui/src/components/chat/ChatInput.tsx +++ b/packages/ui/src/components/chat/ChatInput.tsx @@ -431,7 +431,7 @@ const PermissionAutoAcceptButton = React.memo(function PermissionAutoAcceptButto } return ( - + {button} @@ -454,7 +454,7 @@ const FocusModeButton = React.memo(function FocusModeButton(props: FocusModeButt const { t } = useI18n(); return ( - + - - {isExpanded ? ( -
- -
- ) : null} -
+ + + + {labelHead} + + {t('chat.pendingChanges.changedInWorkspace')} + + + {totalAdded > 0 ? +{totalAdded} : null} + {totalRemoved > 0 ? -{totalRemoved} : null} + + {isExpanded ? ( + + ) : ( + + )} + + } + /> + + + + + + + + ); }); diff --git a/packages/ui/src/components/chat/StatusRow.tsx b/packages/ui/src/components/chat/StatusRow.tsx index 7d15cee4..6b2d1735 100644 --- a/packages/ui/src/components/chat/StatusRow.tsx +++ b/packages/ui/src/components/chat/StatusRow.tsx @@ -87,7 +87,7 @@ const TodoItemRow: React.FC = ({ todo }) => { return (
- + {statusIcon} @@ -103,7 +103,7 @@ const TodoItemRow: React.FC = ({ todo }) => { > {todo.content} - + = ({
- + {showSelectedPreviewButton ? ( - + - + diff --git a/packages/ui/src/components/sections/openchamber/NotificationSettings.tsx b/packages/ui/src/components/sections/openchamber/NotificationSettings.tsx index 8f9b1911..e91bf09b 100644 --- a/packages/ui/src/components/sections/openchamber/NotificationSettings.tsx +++ b/packages/ui/src/components/sections/openchamber/NotificationSettings.tsx @@ -804,7 +804,7 @@ export const NotificationSettings: React.FC = () => {
{t('settings.notifications.page.summary.modelLabel')} - + diff --git a/packages/ui/src/components/sections/openchamber/OpenChamberVisualSettings.tsx b/packages/ui/src/components/sections/openchamber/OpenChamberVisualSettings.tsx index 6ed0308b..93b29462 100644 --- a/packages/ui/src/components/sections/openchamber/OpenChamberVisualSettings.tsx +++ b/packages/ui/src/components/sections/openchamber/OpenChamberVisualSettings.tsx @@ -689,7 +689,7 @@ export const OpenChamberVisualSettings: React.FC > {themesReloading ? t('settings.openchamber.visual.actions.reloadingThemes') : t('settings.openchamber.visual.actions.reloadThemes')} - + -
- - {description} - +
{formBody}
+ -
-
- - {title} - -

- {description} -

-
-
- - -
- {formBody} -
-
- -
-
- {footerRow} -
-
- - - +
+
{footerRow}
+
+ + ); } diff --git a/packages/ui/src/components/session/ScheduledTasksDialog.tsx b/packages/ui/src/components/session/ScheduledTasksDialog.tsx index 3af907cc..a4a59fb2 100644 --- a/packages/ui/src/components/session/ScheduledTasksDialog.tsx +++ b/packages/ui/src/components/session/ScheduledTasksDialog.tsx @@ -192,7 +192,9 @@ export function ScheduledTasksDialog() { const [selectedProjectID, setSelectedProjectID] = React.useState(''); const [tasks, setTasks] = React.useState([]); - const [loading, setLoading] = React.useState(false); + // Start in loading state so the first frame after open shows the spinner, + // not an empty/select-project flash before the fetch effect runs. + const [loading, setLoading] = React.useState(true); const [editorOpen, setEditorOpen] = React.useState(false); const [editorTask, setEditorTask] = React.useState(null); const [mutatingTaskID, setMutatingTaskID] = React.useState(null); @@ -276,6 +278,7 @@ export function ScheduledTasksDialog() { void reloadTasks(preferredProjectID); } else { setTasks([]); + setLoading(false); } }, [open, activeProject, projects, reloadTasks]); @@ -427,6 +430,7 @@ export function ScheduledTasksDialog() { projectSelector )} +
{loading ? (
{t('sessions.scheduledTasks.dialog.loading')} @@ -579,6 +583,7 @@ export function ScheduledTasksDialog() { })}
)} +
); diff --git a/packages/ui/src/components/session/sidebar/sortableItems.tsx b/packages/ui/src/components/session/sidebar/sortableItems.tsx index bd31aec5..33aea845 100644 --- a/packages/ui/src/components/session/sidebar/sortableItems.tsx +++ b/packages/ui/src/components/session/sidebar/sortableItems.tsx @@ -166,7 +166,7 @@ export const SortableProjectItem: React.FC = ({ style={{ backgroundColor: isDesktopShell && isStuck ? 'transparent' : undefined }} >
- + -
- - {t('multiRun.window.description')} - - onOpenChange(false)} - onCancel={() => onOpenChange(false)} - isWindowed - /> - + /> +
+ +
+ +
+ + {t('multiRun.window.description')} + + onOpenChange(false)} + onCancel={() => onOpenChange(false)} + isWindowed + /> +
+
); diff --git a/packages/ui/src/components/views/PlanView.tsx b/packages/ui/src/components/views/PlanView.tsx index 3b1964fb..0dd0a3ce 100644 --- a/packages/ui/src/components/views/PlanView.tsx +++ b/packages/ui/src/components/views/PlanView.tsx @@ -628,7 +628,7 @@ export const PlanView: React.FC = ({ targetPath = null }) => { {resolvedPath ? (
- +
diff --git a/packages/ui/src/components/views/git/HistoryCommitRow.tsx b/packages/ui/src/components/views/git/HistoryCommitRow.tsx index 223b83e0..24fe26de 100644 --- a/packages/ui/src/components/views/git/HistoryCommitRow.tsx +++ b/packages/ui/src/components/views/git/HistoryCommitRow.tsx @@ -88,7 +88,7 @@ export const HistoryCommitRow = React.memo(({ {entry.hash.slice(0, 8)} - +