Skip to content

feat(tabbar): collapse split buttons into an overflow menu - #142

Open
austinywang wants to merge 1 commit into
mainfrom
issue-4331-overflow-menu-on-main
Open

austinywang wants to merge 1 commit into
mainfrom
issue-4331-overflow-menu-on-main

Conversation

@austinywang

@austinywang austinywang commented Jun 1, 2026 •

Copy link
Copy Markdown

Adds Appearance.collapseSplitButtonsIntoMenu; when set, the tab bar's right-side action buttons render as a single ellipsis (⋯) menu (labels from each button's tooltip) instead of a row, with the action lane sized for one button. Reuses performSplitActionButton dispatch. Pinned by cmux PR #4332.

🤖 Generated with Claude Code


View with Codesmith Autofix with Codesmith
Need help on this PR? Tag @codesmith with what you need. Autofix is disabled.


Summary by cubic

Adds an option to collapse the tab bar’s right-side action buttons into a single "⋯" overflow menu. Reserves space for one button and aligns with the overflow-menu requirement in Linear 4331.

  • New Features

    • Introduces Appearance.collapseSplitButtonsIntoMenu (default false).
    • Renders a single "⋯" Menu with labels from each button’s tooltip and reuses performSplitActionButton.
    • Adds accessibility identifier paneTabBarControl.overflowMenu.
  • Migration

    • Opt-in: set appearance.collapseSplitButtonsIntoMenu = true to enable.

Written for commit 5be7109. Summary will update on new commits.

Review in cubic

Summary by CodeRabbit

  • New Features
    • Added a new configuration option to collapse split action buttons in the tab bar into a single overflow menu button. When enabled, individual split action buttons are hidden and consolidated into a "⋯" menu, with each action's tooltip displayed as a menu item label, providing improved interface compactness and better space utilization.

Add Appearance.collapseSplitButtonsIntoMenu; when set, the tab bar's
right-side action buttons render as a single ellipsis menu (labels from
each button's tooltip) instead of a row, with the action lane sized for
one button. Reuses performSplitActionButton dispatch.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@coderabbitai

coderabbitai Bot commented Jun 1, 2026 •

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 41690e9e-e8f8-485a-b34c-239428e25e2b

📥 Commits

Reviewing files that changed from the base of the PR and between ddb46fe and 5be7109.

📒 Files selected for processing (2)
  • Sources/Bonsplit/Internal/Views/TabBarView.swift
  • Sources/Bonsplit/Public/BonsplitConfiguration.swift

📝 Walkthrough

Walkthrough

This PR introduces a split-button menu collapse feature. The tab bar's right-side action buttons now collapse into a single overflow "⋯" menu when enabled via collapseSplitButtonsIntoMenu. The configuration is wired through to adjust lane sizing and conditionally render buttons inline or as menu items.

Changes

Split-button menu collapse

Layer / File(s) Summary
Menu collapse configuration contract
Sources/Bonsplit/Public/BonsplitConfiguration.swift
BonsplitConfiguration.Appearance gains a new collapseSplitButtonsIntoMenu: Bool = false property with documentation and initializer parameter, enabling users to configure the overflow menu behavior.
TabBarView lane sizing and rendering
Sources/Bonsplit/Internal/Views/TabBarView.swift
TabBarView computes effectiveSplitButtonCount based on the collapse setting, updates lane sizing to reserve width for either a single menu button or all buttons, and replaces the split-button row with conditional rendering: inline HStack when disabled or overflow Menu when enabled.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~12 minutes

Possibly related PRs

  • manaflow-ai/bonsplit#123: Both PRs modify split-button lane sizing logic in TabBarView—main PR adds menu-collapse behavior while the retrieved PR adjusts trailing whitespace/width capping to prevent split-action lane clipping.
  • manaflow-ai/bonsplit#140: Both PRs modify TabBarView's split-button implementation—main PR adds menu-collapse rendering while the retrieved PR adjusts split-button icon font/size scaling to match appearance.tabTitleFontSize.

Poem

🐰 Buttons dance and collapse with grace,
One menu blooms in a tiny space,
Config flips, and the menu unfurls,
Swift shows tooltips in nested swirls!

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 33.33% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and specifically describes the main change: adding a feature to collapse split buttons into an overflow menu, which aligns with the core modifications to TabBarView and BonsplitConfiguration.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch issue-4331-overflow-menu-on-main

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@greptile-apps

greptile-apps Bot commented Jun 1, 2026

Copy link
Copy Markdown

Greptile Summary

This PR adds Appearance.collapseSplitButtonsIntoMenu, a new opt-in flag that collapses the tab bar's right-side action buttons into a single ⋯ Menu instead of an inline icon row, with the action lane narrowed to one-button width via the new effectiveSplitButtonCount computed property.

  • TabBarView gains splitButtonOverflowMenu and splitActionButtonMenuLabel helpers; splitButtonRow branches on the flag using a Group, and effectiveSplitButtonCount drives lane sizing to 1 when the menu is active.
  • BonsplitConfiguration.Appearance gains collapseSplitButtonsIntoMenu: Bool (default false) with doc-comment, init parameter, and assignment — a purely additive public API change.

Confidence Score: 3/5

Safe to merge for the common case, but accessibility identifiers on the individual action buttons break silently when the menu is active, which could blind existing UI automation.

The core layout logic (effectiveSplitButtonCount, lane sizing, action dispatch) is correct. Accessibility identifiers placed on Button views inside Menu {} on macOS are bridged to NSMenuItem and typically do not surface in the AX hierarchy under the same identifier path, so existing automation targeting paneTabBarControl.newTerminal etc. will silently miss when the flag is on. The ellipsis trigger is also hardcoded at 12pt rather than scaling with controlIconFontScale, creating a visual mismatch when tabTitleFontSize is customized.

TabBarView.swift — specifically the splitButtonOverflowMenu function and the accessibility identifier modifiers applied to menu item Buttons.

Important Files Changed

Filename Overview
Sources/Bonsplit/Internal/Views/TabBarView.swift Adds splitButtonOverflowMenu and splitActionButtonMenuLabel helpers; replaces the flat HStack in splitButtonRow with a conditional that renders a single Menu when collapseSplitButtonsIntoMenu is set. Introduces effectiveSplitButtonCount to size the action lane to one button in that mode. The ellipsis trigger icon is hardcoded at 12pt instead of using controlIconFontScale, and accessibility identifiers applied to Button items inside Menu {} on macOS may not propagate to their NSMenuItem counterparts.
Sources/Bonsplit/Public/BonsplitConfiguration.swift Adds collapseSplitButtonsIntoMenu: Bool (default false) to Appearance, with matching stored property, init parameter, and doc-comment. Additive public API change; no breaking changes.

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart TD
    A[splitButtonRow] --> B{collapseSplitButtonsIntoMenu AND buttons not empty?}
    B -- Yes --> C[splitButtonOverflowMenu single menu button]
    B -- No --> D[HStack of individual SplitActionButtons]
    C --> E[Menu items via ForEach using splitActionButtonMenuLabel]
    E --> F[performSplitActionButton dispatch]
    D --> F
    G[effectiveSplitButtonCount] --> H{collapseSplitButtonsIntoMenu?}
    H -- Yes, count gt 0 --> I[returns 1]
    H -- No --> J[returns visibleSplitButtons.count]
    I --> K[TabBarLayout sizes lane for 1 button]
    J --> K
Loading

Reviews (1): Last reviewed commit: "feat(tabbar): collapse split buttons int..." | Re-trigger Greptile

Comment on lines 1772 to 1779
ForEach(buttons.indices, id: \.self) { index in
let button = buttons[index]
Button {
performSplitActionButton(button)
} label: {
splitActionButtonIcon(button.icon)
splitActionButtonMenuLabel(button, tooltips: tooltips)
}
.buttonStyle(SplitActionButtonStyle(appearance: appearance, layout: tabBarLayout))
.accessibilityIdentifier(splitActionButtonAccessibilityIdentifier(button))

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Accessibility identifiers on menu items may be unreachable in UI tests

On macOS, Button views inside a SwiftUI Menu {} block are bridged to NSMenuItem rather than rendered as standalone NSViews. .accessibilityIdentifier(_:) modifiers applied to those Button instances typically do not propagate to the resulting NSMenuItem's AXIdentifier in the accessibility hierarchy — the accessibility tree for NSMenuItems is structured differently from regular view hierarchies. Any existing XCTest UI-automation that queries paneTabBarControl.newTerminal, paneTabBarControl.splitRight, etc. by identifier will silently fail to find the elements when collapseSplitButtonsIntoMenu is true, because those identifiers will no longer exist in the expected place in the tree.

Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!

Comment on lines +1781 to +1785
} label: {
Image(systemName: "ellipsis")
.font(.system(size: 12))
}
.menuStyle(.button)

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 The ellipsis trigger icon is hardcoded to 12pt, but every other split-action icon is rendered at 12 * controlIconFontScale so it adapts when the host app sets a custom tabTitleFontSize. With this change, enabling the overflow menu alongside a non-default font size will produce an icon that is visually out of proportion with the rest of the tab bar controls.

Suggested change
} label: {
Image(systemName: "ellipsis")
.font(.system(size: 12))
}
.menuStyle(.button)
} label: {
Image(systemName: "ellipsis")
.font(.system(size: 12 * controlIconFontScale))
}
.menuStyle(.button)

Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

1 issue found across 2 files

Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name="Sources/Bonsplit/Internal/Views/TabBarView.swift">

<violation number="1" location="Sources/Bonsplit/Internal/Views/TabBarView.swift:1783">
P3: Scale the overflow ellipsis icon with `controlIconFontScale` so it remains proportionate when the host app uses a non-default tab title font size.</violation>
</file>

Reply with feedback, questions, or to request a fix.

Re-trigger cubic

}
} label: {
Image(systemName: "ellipsis")
.font(.system(size: 12))

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P3: Scale the overflow ellipsis icon with controlIconFontScale so it remains proportionate when the host app uses a non-default tab title font size.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At Sources/Bonsplit/Internal/Views/TabBarView.swift, line 1783:

<comment>Scale the overflow ellipsis icon with `controlIconFontScale` so it remains proportionate when the host app uses a non-default tab title font size.</comment>

<file context>
@@ -1727,22 +1736,73 @@ struct TabBarView: View {
             }
+        } label: {
+            Image(systemName: "ellipsis")
+                .font(.system(size: 12))
+        }
+        .menuStyle(.button)
</file context>
Suggested change
.font(.system(size: 12))
.font(.system(size: 12 * controlIconFontScale))

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant