Make sure the Tab Rail's background matches the split view's detail background. (#6003)

This commit is contained in:
Doug
2026-08-11 11:07:24 +01:00
committed by GitHub
parent d57c376b21
commit 2228da3eb9
6 changed files with 59 additions and 12 deletions
@@ -385,15 +385,18 @@ private struct NavigationSplitCoordinatorView: View {
/// The NavigationSplitView that will be used in non-compact layouts
var navigationSplitView: some View {
NavigationSplitView(columnVisibility: $navigationSplitCoordinator.columnVisibility) {
if let sidebarModule = navigationSplitCoordinator.sidebarModule {
sidebarModule.coordinator?.toPresentable()
.environment(\.isInSidebar, true)
.id(sidebarModule.id)
} else {
navigationSplitCoordinator.placeholderModule.coordinator?.toPresentable()
.environment(\.isInSidebar, true)
.id(navigationSplitCoordinator.placeholderModule.id)
Group {
if let sidebarModule = navigationSplitCoordinator.sidebarModule {
sidebarModule.coordinator?.toPresentable()
.id(sidebarModule.id)
} else {
navigationSplitCoordinator.placeholderModule.coordinator?.toPresentable()
.id(navigationSplitCoordinator.placeholderModule.id)
}
}
.environment(\.isInSidebar, true)
// The tab rail's background tracks the detail module, so exclude the sidebar's background value.
.transformPreference(CompoundBackgroundPreferenceKey.self) { $0 = nil }
} detail: {
if let detailModule = navigationSplitCoordinator.detailModule {
detailModule.coordinator?.toPresentable()
@@ -316,6 +316,7 @@ private struct NavigationTabCoordinatorView<Tag: Hashable>: View {
@State private var window: UIWindow?
@State private var isFullScreen = true
@State private var isRailVisible = true
@State private var railBackgroundColor: Color = .compound.bgCanvasDefault
var body: some View {
tabView
@@ -362,6 +363,8 @@ private struct NavigationTabCoordinatorView<Tag: Hashable>: View {
HStack(spacing: 0) {
if isRailVisible {
TabRailView(navigationTabCoordinator: navigationTabCoordinator, isFullScreen: isFullScreen)
.background(railBackgroundColor.ignoresSafeArea())
.animation(.easeInOut(duration: 0.4).disabledDuringTests(), value: railBackgroundColor)
}
if let module = navigationTabCoordinator.tabModules.first(where: { $0.details.tag == navigationTabCoordinator.selectedTab }) {
@@ -369,6 +372,10 @@ private struct NavigationTabCoordinatorView<Tag: Hashable>: View {
.id(module.id)
}
}
// Match the rail's background to the colour of the split view's detail (or the root if there isn't a split).
.onPreferenceChange(CompoundBackgroundPreferenceKey.self) { background in
railBackgroundColor = background?.colorValue ?? .compound.bgCanvasDefault
}
.introspect(.window, on: .supportedVersions) { window in
guard self.window !== window else { return }
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:f3e7c2cb5fbbdbccf317f49936f2df84e9247d6e40e6cf1662c79c6bcc9ad4cd
size 358569
oid sha256:db70cf216901b52c1f188338a6671cdf41ddcb755f65fe9ebcd8ed6cb148ff11
size 347369
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:550a193e6ac71694015cba80d705bcac7d90ac8b73cccdd7aae63e762aa59092
size 266276
oid sha256:39bd09601f6a3c332220d821b8648b35c1ff4d64ebfcd729c3941e4f119cff19
size 261578
@@ -0,0 +1,35 @@
//
// Copyright 2026 Element Creations Ltd.
//
// SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial.
// Please see LICENSE files in the repository root for full details.
//
import SwiftUI
/// The reported background drawn by a view.
public enum CompoundBackground: Equatable {
/// A specific background colour.
case color(Color)
/// The default canvas background.
case `default`
public var colorValue: Color {
switch self {
case .color(let color): color
case .default: .compound.bgCanvasDefault
}
}
}
/// A background reported up the hierarchy by a view that opts in, so that surrounding chrome (e.g. the
/// tab rail that sits alongside iOS 26's inset sidebar) can match that view's canvas.
public struct CompoundBackgroundPreferenceKey: PreferenceKey {
public static let defaultValue: CompoundBackground? = nil
public static func reduce(value: inout CompoundBackground?, nextValue: () -> CompoundBackground?) {
if let nextValue = nextValue() {
value = nextValue
}
}
}
@@ -24,11 +24,13 @@ public extension View {
environment(\.defaultMinListRowHeight, 48)
.scrollContentBackground(.hidden)
.background(Color.compound.bgSubtleSecondaryLevel0.ignoresSafeArea())
.preference(key: CompoundBackgroundPreferenceKey.self, value: .color(.compound.bgSubtleSecondaryLevel0))
case .plain:
listStyle(.plain)
.environment(\.defaultMinListRowHeight, 48)
.scrollContentBackground(.hidden)
.background(Color.compound.bgCanvasDefault.ignoresSafeArea())
.preference(key: CompoundBackgroundPreferenceKey.self, value: .default)
}
}