Skip to content

Tahoe 26 Liquid Glass: hide tab bar when tabBarHeight is 0; fix split divider position - #95

Open
rodchristiansen wants to merge 2 commits into
manaflow-ai:mainfrom
rodchristiansen:cmux-tahoe26-liquid-glass
Open

rodchristiansen wants to merge 2 commits into
manaflow-ai:mainfrom
rodchristiansen:cmux-tahoe26-liquid-glass

Conversation

@rodchristiansen

@rodchristiansen rodchristiansen commented Apr 14, 2026 •

Copy link
Copy Markdown

Companion to cmux #2647 (Adopt macOS 26 Liquid Glass design). cmux #2647 pins to this bonsplit SHA; merging here lets it bump pointer back to manaflow-ai/bonsplit#main.

Summary

  • Fix split divider ignoring configured position — split divider was snapping to the default position instead of the value supplied via setDividerPosition, visible when restoring a split from saved state
  • Hide tab bar when tabBarHeight is 0, show only when 2+ tabs — on macOS 26, cmux hides the tab bar on single-tab panes for the cleaner Liquid Glass look, then re-shows it when a second tab is added. Previously the tab bar was forced on regardless of pane tab count

Test plan

  • Open a split, save layout, relaunch — divider lands at the saved position
  • On macOS 26 with tabBarHeight = 0, single-tab pane shows no tab bar; opening a second tab in that pane restores the tab bar
  • Single-tab pane on macOS ≤ 15 (default tabBarHeight) still shows the tab bar as before
  • cmux PR #2647 green after pointer bumps to merged SHA

Summary by cubic

Implements macOS 26 Liquid Glass behavior by hiding the tab bar when tabBarHeight is 0 and only one tab is present. Fixes split divider to honor the configured position during animations and on restore.

  • New Features

    • Hide the tab bar when tabBarHeight = 0 and the pane has a single tab; show it once there are 2+ tabs.
  • Bug Fixes

    • Use the configured splitState.dividerPosition instead of a hardcoded 0.5, so restored layouts and animated inserts land at the correct position.

Written for commit cfff8a9. Summary will update on new commits.

The animated code path hardcoded 0.5 for both the animation
target and the completion handler, overriding whatever ratio
splitState.dividerPosition was set to. Use the configured
position instead.
Copilot AI review requested due to automatic review settings April 14, 2026 18:45
@coderabbitai

coderabbitai Bot commented Apr 14, 2026

Copy link
Copy Markdown

Warning

Rate limit exceeded

@rodchristiansen has exceeded the limit for the number of commits that can be reviewed per hour. Please wait 59 minutes and 9 seconds before requesting another review.

Your organization is not enrolled in usage-based pricing. Contact your admin to enable usage-based pricing to continue reviews beyond the rate limit, or try again in 59 minutes and 9 seconds.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 71f247ae-6351-44f8-9d56-59a192595208

📥 Commits

Reviewing files that changed from the base of the PR and between 2979ef6 and cfff8a9.

📒 Files selected for processing (2)
  • Sources/Bonsplit/Internal/Views/PaneContainerView.swift
  • Sources/Bonsplit/Internal/Views/SplitContainerView.swift
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

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 Apr 14, 2026

Copy link
Copy Markdown

Greptile Summary

This PR delivers two fixes for the macOS 26 Liquid Glass integration: the tab bar in PaneContainerView is now conditionally rendered (hidden when tabBarHeight == 0 and a pane has ≤ 1 tab, shown when tabs reach 2+), and the split divider position restore bug is resolved by making syncPosition compare the live view position against the model in addition to lastAppliedPosition, while updateNSView now explicitly reads dividerPosition to register a SwiftUI dependency so external setDividerPosition calls trigger a re-sync. Both changes are logically sound with no issues found beyond a minor comment wording nit.

Confidence Score: 5/5

  • Safe to merge — both changes are narrowly scoped, well-guarded, and introduce no data loss or correctness risk.
  • All findings are P2 (a one-word comment fix). The core logic for tab bar visibility is correct, SwiftUI reactivity via @bindable is properly wired, and the dual-condition guard in syncPosition correctly handles structural-update drift without introducing redundant syncs under normal operation.
  • No files require special attention.

Important Files Changed

Filename Overview
Sources/Bonsplit/Internal/Views/PaneContainerView.swift Wraps TabBarView in a conditional guard: hidden when tabBarHeight == 0 AND pane.tabs.count <= 1. Logic is correct; SwiftUI reactivity on @bindable pane.tabs.count is sound. Minor comment inaccuracy (says "only one tab" but the guard also covers the zero-tab case).
Sources/Bonsplit/Internal/Views/SplitContainerView.swift Two-part fix for divider position restoration: (1) syncPosition now also compares the actual current view pixel position against the model, so it re-applies even when lastAppliedPosition already matches; (2) updateNSView accesses dividerPosition directly to register a SwiftUI dependency so external setDividerPosition calls trigger updateNSView. Logic and guards are sound.

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart TD
    A[PaneContainerView.body] --> B{tabBarHeight > 0\nOR tabs.count > 1?}
    B -- Yes --> C[Render TabBarView\n+showSplitButtons]
    B -- No\ntabBarHeight==0 AND count ≤ 1 --> D[Tab bar hidden]
    C --> E[contentAreaWithDropZones]
    D --> E

    F[syncPosition called] --> G{isAnimating / isSyncing\n/ depth > 0?}
    G -- Yes --> X[return]
    G -- No --> H{arrangedSubviews < 2\nOR availableSize == 0?}
    H -- Yes --> X
    H -- No --> I[clamp statePosition]
    I --> J[read currentNormalized\nfrom live subview frame]
    J --> K{both within 0.01\nof lastAppliedPosition?}
    K -- Yes --> X
    K -- No --> L[setPositionSafely\nupdate lastAppliedPosition]
Loading

Reviews (1): Last reviewed commit: "Hide tab bar when tabBarHeight is 0, sho..." | Re-trigger Greptile

isFocused: isFocused,
showSplitButtons: showSplitButtons
)
// Tab bar: hidden when tabBarHeight is 0 AND only one tab in pane

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 Comment says "only one tab" but condition covers zero tabs

The inline comment says the tab bar is hidden "when tabBarHeight is 0 AND only one tab in pane," but the guard pane.tabs.count > 1 also suppresses the tab bar when count == 0. That's almost certainly the right call (no point showing an empty tab bar), but the comment is misleading. Consider:

Suggested change
// Tab bar: hidden when tabBarHeight is 0 AND only one tab in pane
// Tab bar: hidden when tabBarHeight is 0 AND pane has 0 or 1 tabs

Copilot AI 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.

Pull request overview

This PR adjusts Bonsplit’s split-view and pane chrome behavior to better support the macOS 26 “Liquid Glass” companion integration in cmux—preserving configured divider positions on entry and conditionally hiding the tab bar for single-tab panes when configured.

Changes:

  • Use the configured splitState.dividerPosition during split entry animation instead of forcing a 0.5 default.
  • Conditionally render TabBarView when tabBarHeight == 0 only if the pane has 2+ tabs (otherwise hide it).

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 1 comment.

File Description
Sources/Bonsplit/Internal/Views/SplitContainerView.swift Fixes entry animation to respect the persisted/configured divider ratio and keeps coordinator state in sync.
Sources/Bonsplit/Internal/Views/PaneContainerView.swift Hides the tab bar for single-tab panes when appearance.tabBarHeight == 0, showing it again once multiple tabs exist.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +172 to +179
// Tab bar: hidden when tabBarHeight is 0 AND only one tab in pane
if bonsplitController.configuration.appearance.tabBarHeight > 0 || pane.tabs.count > 1 {
TabBarView(
pane: pane,
isFocused: isFocused,
showSplitButtons: showSplitButtons
)
}

Copilot AI Apr 14, 2026

Copy link

Choose a reason for hiding this comment

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

tabBarHeight is documented as a height setting, but here it’s effectively being used as a boolean/sentinel to control tab bar visibility (and TabBarView uses a fixed TabBarMetrics.barHeight). This makes tabBarHeight = 0 mean “auto-hide on single tab” rather than “0pt height”, which is surprising for API consumers. Consider introducing an explicit appearance option for tab bar visibility (e.g., enum/flag like tabBarVisibility: .always/.auto/.hidden) and/or updating the configuration API/docs to match the actual behavior.

Copilot uses AI. Check for mistakes.

@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.

No issues found across 2 files

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.

2 participants