Files
TUIkit/Sources/TUIkit/Modifiers/LifecycleModifier.swift
T
phranck 3fb4944472 Refactor: Move runtime services from RenderContext to EnvironmentValues
- Add ServiceEnvironment.swift with 9 EnvironmentKeys for runtime services
  (stateStorage, lifecycle, keyEventDispatcher, renderCache, preferenceStorage,
  pulsePhase, cursorTimer, focusIndicatorColor, activeFocusSectionID)
- Remove tuiContext, pulsePhase, cursorTimer, focusIndicatorColor, and
  activeFocusSectionID as direct RenderContext properties
- Inject all services through EnvironmentValues in RenderLoop.buildEnvironment()
- Add convenience RenderContext init that accepts TUIContext and auto-injects
  services into the environment
- Simplify isolatedForBackground() to only swap environment values
- Migrate ~49 access sites in ~25 source files from context.tuiContext.X and
  context.pulsePhase/cursorTimer to context.environment.X
- Update 38 test files to use the new convenience init
2026-02-14 13:13:24 +01:00

114 lines
3.1 KiB
Swift
Raw Blame History

This file contains invisible Unicode characters
This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
// 🖥 TUIKit Terminal UI Kit for Swift
// LifecycleModifier.swift
//
// Created by LAYERED.work
// License: MIT
// MARK: - OnAppear Modifier
/// A modifier that executes an action when a view first appears.
struct OnAppearModifier<Content: View>: View {
/// The content view.
let content: Content
/// Unique token to track this view's lifecycle.
let token: String
/// The action to execute on first appearance.
let action: () -> Void
var body: Never {
fatalError("OnAppearModifier renders via Renderable")
}
}
extension OnAppearModifier: Renderable {
func renderToBuffer(context: RenderContext) -> FrameBuffer {
// Record appearance and execute action if first time
_ = context.environment.lifecycle!.recordAppear(token: token, action: action)
// Render content
return TUIkit.renderToBuffer(content, context: context)
}
}
// MARK: - OnDisappear Modifier
/// A modifier that executes an action when a view disappears.
struct OnDisappearModifier<Content: View>: View {
/// The content view.
let content: Content
/// Unique token to track this view's lifecycle.
let token: String
/// The action to execute when the view disappears.
let action: () -> Void
var body: Never {
fatalError("OnDisappearModifier renders via Renderable")
}
}
extension OnDisappearModifier: Renderable {
func renderToBuffer(context: RenderContext) -> FrameBuffer {
// Register the disappear callback
context.environment.lifecycle!.registerDisappear(token: token, action: action)
// Mark as visible in current render
_ = context.environment.lifecycle!.recordAppear(token: token, action: {})
// Render content
return TUIkit.renderToBuffer(content, context: context)
}
}
// MARK: - Task Modifier
/// A modifier that starts an async task when a view appears.
///
/// The task is cancelled when the view disappears.
struct TaskModifier<Content: View>: View {
/// The content view.
let content: Content
/// Unique token to track this view's lifecycle.
let token: String
/// The async task to execute.
let task: @Sendable () async -> Void
/// Task priority.
let priority: TaskPriority
var body: Never {
fatalError("TaskModifier renders via Renderable")
}
}
extension TaskModifier: Renderable {
func renderToBuffer(context: RenderContext) -> FrameBuffer {
let lifecycle = context.environment.lifecycle!
// Start task on first appearance
let isFirstAppear = !lifecycle.hasAppeared(token: token)
_ = lifecycle.recordAppear(token: token) {
// Only start task on first appear
}
if isFirstAppear {
lifecycle.startTask(token: token, priority: priority, operation: task)
}
// Register disappear callback to cancel task
lifecycle.registerDisappear(token: token) { [lifecycle] in
lifecycle.cancelTask(token: token)
}
// Render content
return TUIkit.renderToBuffer(content, context: context)
}
}