From 459a0289c199f138be22a3bf0e11f89f9fdc758c Mon Sep 17 00:00:00 2001 From: Lawrence Chen <54008264+lawrencecchen@users.noreply.github.com> Date: Thu, 12 Mar 2026 03:27:10 -0700 Subject: [PATCH] Fix titlebar shortcut hint clipping (#1259) * Add regression test for titlebar shortcut hint clipping * Fix titlebar shortcut hint clipping --- Sources/Update/UpdateTitlebarAccessory.swift | 14 ++++++++++---- cmuxTests/UpdatePillReleaseVisibilityTests.swift | 15 +++++++++++++++ 2 files changed, 25 insertions(+), 4 deletions(-) diff --git a/Sources/Update/UpdateTitlebarAccessory.swift b/Sources/Update/UpdateTitlebarAccessory.swift index 1df2b75a..984df39c 100644 --- a/Sources/Update/UpdateTitlebarAccessory.swift +++ b/Sources/Update/UpdateTitlebarAccessory.swift @@ -193,6 +193,14 @@ struct ShortcutHintHorizontalPlanner { } } +func titlebarShortcutHintHeight(for config: TitlebarControlsStyleConfig) -> CGFloat { + max(14, config.iconSize + 1) +} + +func titlebarShortcutHintVerticalOffset(for config: TitlebarControlsStyleConfig) -> CGFloat { + max(0, floor(config.buttonSize - titlebarShortcutHintHeight(for: config))) +} + struct TitlebarControlButton: View { let config: TitlebarControlsStyleConfig let action: () -> Void @@ -240,7 +248,6 @@ struct TitlebarControlsView: View { @StateObject private var modifierKeyMonitor = TitlebarShortcutHintModifierMonitor() private let titlebarHintRightSafetyShift: CGFloat = 10 private let titlebarHintBaseXShift: CGFloat = -10 - private let titlebarHintBaseYShift: CGFloat = 1 private enum HintSlot: Int, CaseIterable { case toggleSidebar @@ -304,7 +311,7 @@ struct TitlebarControlsView: View { } private func titlebarHintVerticalBaseOffset(for config: TitlebarControlsStyleConfig) -> CGFloat { - max(8, config.buttonSize * 0.4) + titlebarShortcutHintVerticalOffset(for: config) } @ViewBuilder @@ -452,7 +459,6 @@ struct TitlebarControlsView: View { ) -> some View { let yOffset = config.groupPadding.top + titlebarHintVerticalBaseOffset(for: config) - + titlebarHintBaseYShift + ShortcutHintDebugSettings.clamped(titlebarShortcutHintYOffset) ZStack(alignment: .topLeading) { @@ -480,7 +486,7 @@ struct TitlebarControlsView: View { .foregroundColor(.primary) .padding(.horizontal, 6) .padding(.vertical, 2) - .frame(minHeight: max(14, config.iconSize + 1)) + .frame(minHeight: titlebarShortcutHintHeight(for: config)) .background(ShortcutHintPillBackground()) } diff --git a/cmuxTests/UpdatePillReleaseVisibilityTests.swift b/cmuxTests/UpdatePillReleaseVisibilityTests.swift index 96826edf..1225c111 100644 --- a/cmuxTests/UpdatePillReleaseVisibilityTests.swift +++ b/cmuxTests/UpdatePillReleaseVisibilityTests.swift @@ -166,6 +166,21 @@ final class TitlebarControlsSizingPolicyTests: XCTestCase { ) XCTAssertTrue(titlebarControlsShouldApplyLayout(previous: baseline, next: changed)) } + + func testShortcutHintVerticalOffsetKeepsPillInsideButtonLane() { + for style in TitlebarControlsStyle.allCases { + let config = style.config + let hintHeight = titlebarShortcutHintHeight(for: config) + let verticalOffset = titlebarShortcutHintVerticalOffset(for: config) + + XCTAssertGreaterThanOrEqual(verticalOffset, 0, "Expected non-negative hint offset for style \(style)") + XCTAssertLessThanOrEqual( + verticalOffset + hintHeight, + config.buttonSize, + "Expected hint pill to fit within the titlebar button lane for style \(style)" + ) + } + } } final class TitlebarControlsHoverPolicyTests: XCTestCase {