Files
TUIkit/Sources/TUIkitExample/Pages/ButtonsPage.swift
T
phranck 50825d61da Feat: Structural identity for @State — persistent state across view reconstruction
Implement SwiftUI-style structural identity so @State values survive
full view-tree reconstruction on every render pass. State is keyed by
ViewIdentity (path-based) and property index in a central StateStorage.

- Add ViewIdentity (path-based structural identity for views)
- Add StateStorage with GC and branch invalidation
- Refactor @State to self-hydrate from StateStorage during init
- Set root hydration context in RenderLoop before app.body evaluation
- Extend RenderContext with identity propagation helpers
- Add ConditionalView branch invalidation on switch
- Remove scene cache from RenderLoop (app.body evaluated fresh per frame)
- Enhance Example App pages with @State (ButtonsPage, OverlaysPage, ContainersPage)
- Update DocC articles (StateManagement, RenderCycle)
- Add 12 tests for state storage identity
2026-02-02 18:31:53 +01:00

94 lines
2.9 KiB
Swift

//
// ButtonsPage.swift
// TUIkitExample
//
// Demonstrates button and focus system capabilities.
//
import TUIkit
/// Buttons and focus demo page.
///
/// Shows interactive button features including:
/// - Different button styles (default, primary, success, destructive)
/// - Disabled buttons
/// - Plain style (no border)
/// - ButtonRow for horizontal groups
/// - Focus navigation with Tab
/// - Live click counter demonstrating `@State` persistence across re-renders
struct ButtonsPage: View {
@State var clickCount: Int = 0
var body: some View {
VStack(spacing: 1) {
HeaderView(title: "Buttons & Focus Demo")
DemoSection("Interactive Counter (@State)") {
HStack(spacing: 2) {
Button("+1", style: .primary) {
clickCount += 1
}
Button("+10", style: .success) {
clickCount += 10
}
Button("Reset", style: .destructive) {
clickCount = 0
}
Text("Clicks: \(clickCount)")
.bold()
.foregroundColor(.palette.accent)
}
}
DemoSection("Button Styles") {
HStack(spacing: 2) {
Button("Default") {
clickCount += 1
}
Button("Primary", style: .primary) {
clickCount += 1
}
Button("Success", style: .success) {
clickCount += 1
}
Button("Destructive", style: .destructive) {
clickCount += 1
}
}
}
DemoSection("Disabled Button") {
HStack(spacing: 2) {
Button("Enabled") { clickCount += 1 }
Button("Disabled") {}.disabled()
}
}
DemoSection("Plain Style (No Border)") {
HStack(spacing: 2) {
Button("Link 1", style: .plain) { clickCount += 1 }
Button("Link 2", style: .plain) { clickCount += 1 }
}
}
DemoSection("ButtonRow (Horizontal Group)") {
ButtonRow(spacing: 3) {
Button("Cancel") { clickCount += 1 }
Button("Save", style: .primary) { clickCount += 1 }
}
}
DemoSection("Focus Navigation") {
VStack {
Text("Use [Tab] to move focus between buttons")
.dim()
Text("Use [Enter] or [Space] to press the focused button")
.dim()
}
}
Spacer()
}
}
}