luminate/Sources/LuminateOnboarding/Environment/OnboardPathEnvironmentKey.swift

70 lines
2.9 KiB
Swift

//
// OnboardPathEnvironmentKey.swift
//
// Copyright 2026 Brendan Szymanski <hello@bscubed.dev>
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
//
// SPDX-License-Identifier: GPL-3.0-or-later
//
import Logging
import LuminateCore
import Portico
private let logger = Logger(label: "\(AppInfo.identifier).onboarding")
/// The environment slot that carries `OnboardWindow`'s navigation path down the onboarding tree.
///
/// The slot holds the `Binding` itself, not the path value: Portico's `@Environment` is a read-only
/// view of a slot, so a consumer can only push by writing through a binding that the injecting
/// window owns. Onboarding-specific by design -- a future main-window stack gets its own slot
/// rather than sharing this one.
package enum OnboardPathEnvironmentKey: EnvironmentKey {
/// The inert binding used when nothing injected a path.
///
/// Reads yield an empty stack and writes are logged and dropped, so a page mounted outside
/// `OnboardWindow` (a unit test, a preview harness) reports the mistake instead of silently
/// appearing to navigate.
package static var defaultValue: Binding<[OnboardDestination]> {
Binding(
get: { [] },
set: { _ in
logger.error("Dropped an onboarding navigation push: no OnboardWindow injected \\.onboardPath")
}
)
}
}
extension EnvironmentValues {
/// The onboarding navigation path visible to this subtree.
///
/// ```swift
/// // Injection, once, on OnboardWindow's NavigationView:
/// NavigationView(path: $onboardPath) { ... }.environment(\.onboardPath, $onboardPath)
///
/// // Consumption in any onboarding page:
/// @Environment(\.onboardPath) private var onboardPath
/// onboardPath.wrappedValue.append(.manualLogin)
/// ```
///
/// The accessors deliberately route through `self[OnboardPathEnvironmentKey.self]`: Portico
/// resolves a key path by reading it with a probe installed and capturing the box the subscript
/// hands over, so a computed property that bypassed the subscript would leave the slot
/// unresolvable.
package var onboardPath: Binding<[OnboardDestination]> {
get { self[OnboardPathEnvironmentKey.self] }
set { self[OnboardPathEnvironmentKey.self] = newValue }
}
}