Commit Graph

15 Commits

Author SHA1 Message Date
phranck db03e4e41c Refactor: HSL-based color system for all palettes — lighter/darker preserve hue, unified baseHue architecture 2026-02-03 18:11:39 +01:00
phranck 186e444fcc Fix: ESC closes modal via StatusBar context switching
OverlaysPage now manages its own StatusBar items based on modal state:
- Modal open: ESC → close modal, Enter → dismiss
- Modal closed: ESC → back to menu, arrows → nav, Enter → show

Removes redundant ESC handlers from Modal/AlertPresentationModifier.
The correct approach is context-aware StatusBar items, not multiple
competing ESC handlers.
2026-02-03 12:35:07 +01:00
phranck ca9a0cf49c Fix: Modal focus isolation, ESC dismiss, footer layout, palette colors
- Wire FocusManager.dispatchKeyEvent() into InputHandler as Layer 3
  (Tab/Shift+Tab navigation, Enter/Space button activation)
- Modal/Alert presenters isolate base content from focus/key systems
  using RenderContext.isolatedForBackground() so only modal buttons
  receive focus and key events
- ESC automatically dismisses any modal or alert (framework-level)
- Fix ContainerView footer layout: Spacer() now fills correctly by
  constraining footer context to actual inner width
- Remove body background color from standard style containers
  (only block style uses distinct section backgrounds)
- Replace all hardcoded ANSI colors with palette semantic colors
  (.palette.warning/error/info/success) in Alert presets and example app
2026-02-03 12:28:39 +01:00
phranck 7e69b9e924 Fix: Right-align dismiss buttons in all overlay demo variants
Changed dismissButton to use HStack { Spacer(); Button } pattern for
consistent right-alignment across all alerts, dialogs, and modals.

Also simplified Alert preset usage — replaced explicit Alert<Button>.warning()
with standard Alert() initializer to avoid generic type inference issues.
2026-02-03 02:22:46 +01:00
phranck 44895b59cc Feat: Redesign OverlaysPage with interactive demo menu
Replace the static single-alert demo with an interactive page featuring:
- Menu with 8 overlay variants (5 Alert presets, 2 Dialog styles, 1 custom modal)
- Description panel showing details and API usage for the selected variant
- Enter key triggers the selected overlay with dimmed background
- Dismiss button closes any overlay

Variants demonstrated:
1. Alert (Standard) — default theme colors
2. Alert (Warning) — yellow preset
3. Alert (Error) — red preset
4. Alert (Info) — cyan preset
5. Alert (Success) — green preset
6. Dialog — content-only, no footer separator
7. Dialog with Footer — footer section with separator line
8. Modal (Custom) — arbitrary view content with .modal(isPresented:)
2026-02-03 02:19:12 +01:00
phranck 82c8eaf4b2 Fix: Enforce absolute SwiftUI API parity for .alert() modifier
Changed .alert() signature to match SwiftUI exactly:
- message parameter is now @ViewBuilder () -> Message (was String)
- Parameter order matches SwiftUI: title, isPresented, actions, message
- Message content is rendered to string internally for Alert view

Updated:
- AlertPresentationModifier generic signature (added Message type parameter)
- View+Presentation.swift API signatures
- OverlaysPage demo to use ViewBuilder message
- All AlertPresentationModifierTests to use ViewBuilder message

Added permanent rule to .claude/CLAUDE.md:
- ABSOLUTE SwiftUI API Parity is non-negotiable
- Must research exact SwiftUI signatures before implementing
- Only deviate when terminal constraints require it

This ensures TUIKit provides a familiar API for SwiftUI developers.
2026-02-03 02:03:39 +01:00
phranck 45503c0d80 Feat: Add SwiftUI-style presentation API with .alert() and .modal(isPresented:)
- Add AlertPresentationModifier with Binding<Bool> support
- Add ModalPresentationModifier for custom modal content
- Add View+Presentation.swift with .alert() and .modal(isPresented:) extensions
- Update OverlaysPage to demonstrate new declarative presentation API
- Add comprehensive tests for both presentation modifiers (13 tests)
- Follows SwiftUI API parity rule: same naming, parameter order, and behavior

The new API eliminates manual if/else branching for modals:

Before:
  if showModal {
    content.dimmed().overlay { AlertView() }
  } else {
    content
  }

After:
  content.alert("Title", isPresented: $showModal) {
    Button("OK") { showModal = false }
  }

This mirrors SwiftUI's .alert(isPresented:) and .sheet(isPresented:) patterns.
2026-02-03 01:34:30 +01:00
phranck 2cdb0dd3db Refactor: Simplify Spinner API — remove speed, track width, and trail length enums
Radically simplify the Spinner public API from 6 parameters to 3.
Remove SpinnerSpeed, BouncingTrackWidth, and BouncingTrailLength enums.
Hardcode calibrated intervals (dots 110ms, line 140ms, bouncing 100ms),
fixed track width (9), and trail opacities with edge overshoot for
smooth fade-in/fade-out at track edges.
2026-02-02 20:25:38 +01:00
phranck dec8c7c29f Feat: Add Spinner view with dots, line, and bouncing styles
Auto-animating loading indicator with three visual styles:
- Dots (braille rotation), Line (ASCII rotation), Bouncing (Larson scanner
  with fade trail). Time-based frame calculation ensures each spinner runs
  at its own speed independent of render triggers.

Configurable: SpinnerSpeed (.slow/.regular/.fast), BouncingTrackWidth
(.minimum/.default/.maximum/.fixed(Int)), BouncingTrailLength
(.short/.regular/.long), custom color.

Run loop upgraded from 100ms to 40ms polling (~25 FPS) to support
smooth animations.
2026-02-02 19:57:58 +01:00
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
phranck 1877ae65e6 Refactor: Eliminate AppState singleton via RenderNotifier and constructor injection 2026-02-02 17:31:52 +01:00
phranck 68fcf47637 Refactor: Restrict access levels to minimize public API surface
Systematically audit and restrict public declarations across the entire
framework. Internal plumbing (rendering, registries, framework services)
is now internal/private while the user-facing API remains public.

Categories changed:
- Rendering infrastructure (Renderable, ANSIRenderer, BorderRenderer,
  Terminal, ViewRenderer) → internal
- Framework services (PreferenceStorage, LifecycleManager, TUIContext,
  KeyEventDispatcher) → internal
- Implementation modifier types (OnAppearModifier, OnDisappearModifier,
  TaskModifier, StatusBarItemsModifier, etc.) → internal
- View properties (Text.content, Button.label, Menu.items, etc.) → internal
- Registries (PaletteRegistry, AppearanceRegistry) → internal
- Styling internals (ANSIColor, SemanticColor, GeneratedPalette.Hue,
  BorderStyle block-styles) → internal
- ContainerView/ContainerConfig/ContainerStyle → fully internal
- ThemeManager.items/init → internal
- ViewBuilder glue types properties/inits → internal

Also includes:
- Doc warnings (/// - Important:) on types public only for technical reasons
- DocC landing page and CustomViews article updated for internal types
- All DocC symbol links to internal types converted to code text (0 warnings)
- README test badge updated to 498
- Example app ContainerView usage replaced with Panel

498 tests passing, 0 DocC warnings.
2026-01-31 14:29:39 +01:00
phranck 9f7092d4c8 Refactor: Replace EnvironmentStorage singleton with semantic colors and deprecate @Environment (Phase 6) 2026-01-31 01:13:31 +01:00
phranck 282d1662c1 Refactor: Eliminate AppState singleton
- Replace AppState.shared with AppState.active (settable static property)
- Make AppState.init() public instead of private
- Update all 15 source references across State.swift, App.swift,
  StatusBarState.swift, ThemeManager.swift, AppStorage.swift
- Update all 28 test references in AppStateTests and StatePropertyTests
- Serialize Environment Property Wrapper tests (shared-state race fix)
2026-01-30 23:08:22 +01:00
phranck 95029184e7 Chore: Rename TUIKit to TUIkit
- Rename module, targets and products in Package.swift
- Rename directories: Sources/TUIkit, TUIkitExample, Tests/TUIkitTests
- Rename files: TUIkit.swift, TUIkit.docc/TUIkit.md
- Update all import statements, module-qualified calls, file headers
- Update doc comments, string literals and DocC articles
- Update CI workflow, README, .swiftlint.yml and markdown docs
- Merge platform badges into single combined badge in README
- Add "Example App auslagern" task to to-dos.md
2026-01-30 20:29:29 +01:00