Commit Graph
39 Commits
Author SHA1 Message Date
phranck fb434fe77d feat(StatusBar): Add appearance system integration
- StatusBar bordered style now uses appearance-based borderStyle
- Replace help item (`?`) with appearance item (`a`) in system items
- Add `showAppearanceItem` flag to StatusBarState
- Add `StatusBarItemOrder.appearance` for proper ordering
- Update SystemStatusBarItem to include appearance cycling
- Pressing `a` now cycles through appearances (line, rounded, doubleLine, heavy, block)

The StatusBar bordered style adapts to the current appearance, showing the
same border style as all other controls in the app.
2026-01-28 22:47:33 +01:00
phranck 6c816a1770 refactor(example): Update Example App to use appearance-based borderStyle
- MainMenuPage: Menu and featureBox now use appearance default
- LayoutPage: Boxes and borders now use appearance default
- OverlaysPage: Alert now uses appearance default borderStyle

This allows the 'a' key shortcut to change the appearance of all
components simultaneously.
2026-01-28 22:44:29 +01:00
phranck f7df2fa2de feat(Menu): Add appearance-based selection highlighting
- Block appearance uses background highlight for selected items
- Other appearances use arrow indicator prefix
- Selected item in block appearance swaps foreground/background colors
2026-01-28 22:43:15 +01:00
phranck 5147951420 fix: Remove ESC as quit shortcut - only 'q' quits the app
ESC should only be used for navigation (back to menu), not for quitting.
The 'q' key is the only way to quit the app.
2026-01-28 22:39:04 +01:00
phranck da3a0a1922 refactor: Remove ascii Appearance (not needed)
Remaining appearances: line, rounded, doubleLine, heavy, block
2026-01-28 22:34:56 +01:00
phranck bb465c8839 refactor: Rename Appearance presets to match BorderStyle names
Changed from invented names to existing BorderStyle names:
- .sharp → .line
- .double → .doubleLine
- Added .block (was missing)

Appearance IDs now match BorderStyle names exactly:
- .line, .rounded, .doubleLine, .heavy, .block, .ascii

Cycling order: line → rounded → doubleLine → heavy → block → ascii
2026-01-28 22:33:18 +01:00
phranck 282585a68b feat: Add Appearance system for consistent UI styling
Appearance controls the visual structure (border style) of UI controls,
while Theme controls colors. Together they create a complete look.

New types:
- Appearance: Defines borderStyle for all controls
- Appearance.ID: Type-safe identifier (no magic strings)
- AppearanceManager: Environment-based cycling (no singleton)
- AppearanceRegistry: Available appearances

Predefined appearances:
- .rounded (default) - Curved corners
- .sharp - 90-degree corners
- .double - Double-line borders
- .heavy - Thick/bold borders
- .ascii - Maximum terminal compatibility (+, -, |)

Updated components to use appearance.borderStyle as default:
- Menu, Button, Panel, Card, Box, Alert, Dialog
- BorderModifier (.border() modifier)

Added 'a' key shortcut to cycle through appearances.

Also added BorderStyle.ascii for ASCII-only terminals.

All 189 tests passing.
2026-01-28 21:44:01 +01:00
phranck 982cfbc39e style: Add subtle theme tint to backgrounds
Each theme now has a darker background with a subtle color tint:
- Green: #0F1A0F (dark with green tint)
- Amber: #1A150F (dark with amber/orange tint)
- White: #121418 (dark with cool/blue tint)
- Red: #1A0F0F (dark with red tint)

This gives each theme a more distinctive character while keeping
the backgrounds dark and easy on the eyes.
2026-01-28 21:25:29 +01:00
phranck 0de5bbd13e fix: Preserve background color after ANSI reset codes
Replace all reset codes in rendered content with 'reset + restore background'
to ensure the theme background persists after styled text ends.

This fixes the issue where text with ANSI formatting would reset the
background color, leaving parts of the terminal with the wrong background.
2026-01-28 21:22:28 +01:00
phranck 497ce9cb56 fix: Apply theme background to all content and status bar
- WindowGroup.renderScene wraps each line with background color code
- StatusBar rendering also uses theme background
- Ensures entire terminal has consistent background color
2026-01-28 21:18:51 +01:00
phranck fd3baee9f7 fix: Fill entire terminal with theme background color
- Add Terminal.fillBackground() method to fill screen with a color
- Add ANSIRenderer.backgroundCode() helper for background escape sequences
- AppRunner now fills screen with theme.background before rendering content
- Remove unnecessary .frame() and .background() from ContentView

This ensures the entire terminal has a consistent background color that
changes when switching themes.
2026-01-28 21:15:41 +01:00
phranck 750561ad76 feat: Add theme background color to Example App
ContentView now fills the entire terminal with the current theme's
background color, providing a consistent look when switching themes.
2026-01-28 21:10:33 +01:00
phranck 3470cb8e24 refactor: Use theme colors throughout UI components
- Update all 4 phosphor themes (Green, Amber, White, Red) to use neutral
  dark background (#1E1E1E) matching Spotnik reference
- Simplify theme names (remove 'Phosphor' suffix)
- Menu: Use theme.foreground for items, theme.accent for selection
- Button: Use theme colors for default focused style and focus indicator
- Panel/Card: Use theme.border as default border color
- BorderModifier: Use theme.border as default

All 189 tests passing.
2026-01-28 21:08:25 +01:00
phranck 1d547a4f19 refactor: Simplify themes - Green as default, remove Light/Dark
- Remove DefaultTheme, DarkTheme, LightTheme
- GreenPhosphorTheme is now the default theme
- Theme cycling order: Green → Amber → White → Red → NCurses
- .default now maps to GreenPhosphorTheme
2026-01-28 20:55:46 +01:00
phranck 201d920bdc fix: Apply ThemeManager's current theme to environment during render
The render() method was creating a new EnvironmentValues with the default
theme, overwriting any theme changes made by ThemeManager. Now the current
theme is explicitly set from themeManager.currentTheme.
2026-01-28 20:51:55 +01:00
phranck f00d919c1f feat: Use theme colors in StatusBar and Example App
- StatusBar now uses theme colors by default (statusBarHighlight, statusBarForeground)
- Example App MainMenuPage uses theme colors (accent, border, foreground*)
- Example App HeaderView uses theme colors
- Theme switching ('t' key) now shows visible changes
2026-01-28 20:50:28 +01:00
phranck 544152de02 refactor: Remove ThemeManager singleton, add Environment-based access
- ThemeManager is no longer a singleton
- Access via Environment: @Environment(\.themeManager)
- Type-safe setTheme() API: themeManager.setTheme(.amber)
- ThemeManager injected by AppRunner into environment
- Custom themes supported via init(themes:)
2026-01-28 20:48:00 +01:00
phranck 1d3c9b2a62 feat: Add QuitBehavior and ThemeManager
QuitBehavior:
- .always: Quit works from any screen (default)
- .rootOnly: Quit only works from main screen (no context pushed)
- Quit item hidden in status bar when not allowed

ThemeManager:
- Singleton for managing theme cycling
- cycleTheme() / cyclePreviousTheme() methods
- setTheme(at:) and setTheme(withId:) for direct access
- Automatically updates environment and triggers re-render
- 't' key now cycles themes in AppRunner
2026-01-28 20:44:00 +01:00
phranck 9c96e96460 feat: Add showHelpItem and showThemeItem flags
- System items are now built dynamically based on flags
- showHelpItem (default: true) - controls ? help visibility
- showThemeItem (default: true) - controls t theme visibility
- Quit item is always shown when showSystemItems is true
- Removed unused configureSystemItems method
2026-01-28 20:42:08 +01:00
phranck b9a6cc29ab fix: Show all system items (quit, help, theme) and fix deduplication
- StatusBarState now initializes with all 3 system items
- Added deduplication logic to StatusBar.renderToBuffer
- User items with same shortcut override system items
- Updated Example App to not duplicate 'q quit'
- Updated tests for 3 system items instead of 1
2026-01-28 20:40:52 +01:00
phranck 61a51ef056 refactor: Two-container model for StatusBar (user left, system right)
- StatusBar now has separate userItems and systemItems properties
- User items are sorted by order, then system items (fixed order) appended
- Rendering combines both: [sorted user items] + [system items]
- User items override system items with same shortcut (deduplication)
- StatusBarState passes items separately to StatusBar
- Alignment applies to the combined items
- Updated tests to use userItems property
2026-01-28 20:32:39 +01:00
phranck 04cbf2db8b feat: Add system StatusBar items with stable ordering
- Add StatusBarItemOrder for consistent item positioning
- System items (quit, help, theme) appear on the right side
- User items appear on the left, can override system items
- Separate tracking of user vs system items in StatusBarState
- Add showSystemItems flag to disable system items in tests
- Items sorted by order value (lower = left, higher = right)
- User items override system items with the same shortcut
- Add comprehensive tests for system item behavior (189 total)
2026-01-28 20:23:27 +01:00
phranck 45e73faafb refactor: Rename package from SwiftTUI to TUIKit
BREAKING CHANGE: Package name changed due to name collision with
existing rensbreur/SwiftTUI package.

Changes:
- Rename package from SwiftTUI to TUIKit in Package.swift
- Rename Sources/SwiftTUI to Sources/TUIKit
- Rename Sources/SwiftTUIExample to Sources/TUIKitExample
- Rename Tests/SwiftTUITests to Tests/TUIKitTests
- Rename SwiftTUI.swift to TUIKit.swift
- Update all imports: import SwiftTUI -> import TUIKit
- Update all code references: SwiftTUI.renderToBuffer -> TUIKit.renderToBuffer
- Update documentation comments
- Rename swiftTUIVersion to tuiKitVersion

All 181 tests passing.
2026-01-28 19:32:09 +01:00
phranck 44d9d4490e refactor: Replace FocusManager singleton with Environment-based injection
- Remove FocusManager.shared singleton pattern
- Add FocusManagerKey for Environment access via \.focusManager
- FocusState now reads from EnvironmentStorage
- AppRunner creates and injects FocusManager instance
- Button accesses FocusManager via context.environment
- Update all tests to use independent FocusManager instances
- Add new test suite for Environment integration
- Tests can now run in parallel (no more --no-parallel needed)

181 tests passing
2026-01-28 19:28:00 +01:00
phranck a53c1a07fd refactor: Remove T prefix from all public types
- Rename TView → View, TApp → App, TScene → Scene
- Rename TState → State, TViewBuilder → ViewBuilder
- Rename TViewModifier → ViewModifier, TViewArray → ViewArray
- Rename TStatusBar* → StatusBar* (Item, Style, Alignment, Protocol)
- Add Theme system with 8 predefined themes (Phosphor, ncurses, Dark, Light)
- Add Color extensions: hex string, HSL, lighter/darker/opacity
- Update all files, example app, and tests for new names
2026-01-28 19:08:50 +01:00
phranck 5a076dbf9b feat: Add lifecycle, storage, preferences and improve layout
- Add @AppStorage and @SceneStorage for persistent settings
- Add @onAppear, @onDisappear and .task() lifecycle modifiers
- Add Preferences system for bottom-up data flow (child → parent)
- Add UserDefaultsStorage with Linux-compatible implementation
- Add flexible .frame() with minWidth/maxWidth/maxHeight/.infinity
- Fix BorderModifier to reduce availableWidth for content
- Fix StatusBar .justified alignment for equal edge spacing
- Fix Alert vertical expansion by removing Spacer
- Fix q-quit not working when StatusBar item has no action
- Fix render loop caused by statusBarItems modifier
- Add Linux compatibility (Glibc, XDG paths)
2026-01-28 18:42:52 +01:00
phranck 0ce0d541b7 feat: Add Environment system and refactor StatusBar to use it
This commit introduces a SwiftUI-like Environment system and refactors
the StatusBar from a singleton pattern to an environment-based architecture.

## Environment System (new)
- EnvironmentKey protocol for defining custom environment values
- EnvironmentValues container with subscript access
- EnvironmentStorage for thread-local storage during rendering
- @Environment property wrapper for reading values in views
- EnvironmentModifier and .environment() modifier for injecting values

## StatusBar Refactoring
- Replaced StatusBarManager singleton with StatusBarState class
- StatusBarState is created by AppRunner and injected via Environment
- Views access StatusBar via @Environment(\.statusBar)
- Removed all singleton-based code from StatusBar.swift

## .statusBarItems() Modifier (new)
- .statusBarItems([...]) - set items from array
- .statusBarItems { ... } - set items with builder syntax
- .statusBarItems(context: "name") { ... } - push items to context stack
- Enables declarative StatusBar configuration per view

## Example App
- ContentView now uses .statusBarItems() modifier declaratively
- AppState simplified - no manual StatusBar reference needed
- Each page declares its own status bar items

## Tests
- 178 tests across 26 suites, all passing
- New tests for StatusBarItemsModifier
- Tests updated for StatusBarState API
2026-01-28 18:12:34 +01:00
phranck 959e7ffb5a feat: Add Shortcut constants for common Unicode symbols
- Add Shortcut enum with predefined Unicode symbols for keyboard shortcuts:
  - Special keys: escape (⎋), enter (↵), tab (⇥), backspace (⌫), etc.
  - Arrow keys: single (↑↓←→) and combinations (↑↓, ←→, ↑↓←→)
  - Modifier keys: command (⌘), option (⌥), control (⌃), shift (⇧)
  - Navigation: home, end, pageUp (⇞), pageDown (⇟)
  - Common shortcuts: quit, yes, no, cancel, ok
- Add helper methods:
  - Shortcut.combine() for combining symbols
  - Shortcut.ctrl() for Ctrl+key display (^c)
  - Shortcut.range() for range display (1-9)
- Update Example App to use Shortcut constants
- Add 9 new tests for Shortcut constants (103 total)
2026-01-28 17:22:00 +01:00
phranck 1c896fb1f8 feat: Add TStatusBar with dynamic context-sensitive shortcuts
- Add TStatusBarItemProtocol for custom status bar items
- Add TStatusBarItem with shortcut, label, and action callback
- Add TStatusBarStyle (compact, bordered) for visual customization
- Add StatusBarManager singleton for context-dependent item management
  - Global items (always shown)
  - Context stack (push/pop for dialogs, modals, etc.)
  - Automatic shortcut handling with case-sensitive matching
- Modify AppRunner to render StatusBar separately (never dimmed by overlays)
- Reserve space for StatusBar in content area calculation
- Add 20 new tests for StatusBar system (94 total)
- Restructure Example App into separate files:
  - main.swift (entry point)
  - AppState.swift (state management)
  - ContentView.swift (page router)
  - Components/ (HeaderView, DemoSection)
  - Pages/ (MainMenuPage, TextStylesPage, ColorsPage, etc.)
2026-01-28 17:16:44 +01:00
phranck 5ca3ce2de1 feat: Add Button view with focus system and keyboard support
- Add FocusManager for tracking which element has focus
- Add Focusable protocol for interactive views
- Add Button view with styles (default, primary, destructive, success, plain)
- Add ButtonRow for horizontal button groups
- Add ButtonStyle with customizable colors, borders, and padding
- Keyboard navigation: Tab to move focus, Enter/Space to activate
- Visual focus indicator (▸) for focused buttons
- Add 16 new tests for Focus and Button systems (74 total)
- Add Buttons & Focus demo page to example app
2026-01-28 16:50:20 +01:00
phranck ddcb918ad5 fix: onKeyPress handler now returns Bool to control event propagation
- Handler must return true if event was consumed, false to propagate
- This fixes 'q' not working to quit the app (was being consumed)
- ESC on sub-pages returns true (consumed), on menu returns false (exits)
2026-01-28 16:44:19 +01:00
phranck 461787a43e fix: ESC for back navigation and menu divider color
- ESC key now goes back to menu (instead of B key)
- ESC only exits app when already on main menu
- Menu divider line now uses same color as border
- Updated footer to show [ESC] Back instead of [B] Back
2026-01-28 16:36:58 +01:00
phranck e3b19fd518 fix: Panel top border and remove ugly border styles
Panel:
- Fixed top border calculation (left corner was missing)
- Added ANSI reset before right border to prevent color bleeding

BorderStyle:
- Removed .dashed, .dotted, and .ascii styles (poor visual quality)
- Remaining styles: .line, .rounded, .doubleLine, .heavy, .block, .none
2026-01-28 16:32:59 +01:00
phranck 97bdc5cf2f feat: Add state management and keyboard event system
State Management:
- @TState property wrapper for reactive state
- Binding<T> for two-way data binding
- AppState singleton for triggering re-renders

Event System:
- KeyEvent model with Key enum (arrows, enter, escape, characters, etc.)
- KeyEvent.parse() for terminal escape sequence parsing
- KeyEventDispatcher for routing events to handlers
- .onKeyPress() modifier for handling keyboard input
- Terminal.readKeyEvent() for reading complete key events

Interactive Menu:
- Menu now accepts selection Binding for interactive navigation
- Arrow keys move selection up/down (with wrap-around)
- Enter key and shortcuts trigger onSelect callback
- Automatic key handler registration during render

Example App:
- Full page navigation between demo screens
- Press [B] to go back to menu from any page
- Arrow keys and number shortcuts for menu navigation
- Footer shows available keyboard shortcuts
2026-01-28 16:09:16 +01:00
phranck 69ea72ac25 fix: Menu divider alignment and center feature boxes
- Menu divider now starts at same column as title text
- Feature boxes on main menu are now horizontally centered
2026-01-28 16:01:37 +01:00
phranck feb4967300 fix: Prevent ANSI color bleeding to right border
- Add ANSI reset before right border character in Menu and BorderModifier
- This prevents colored content from affecting border color
2026-01-28 15:59:59 +01:00
phranck 1bd5856c4d fix: Menu rendering and input handling
- Menu now uses Renderable protocol instead of ForEach in body
  (ForEach rendering in body not fully working yet)
- Input handler now only exits on ESC/q/Q, ignores other keys
- Menu items render correctly with selection indicator and shortcuts
2026-01-28 15:57:16 +01:00
phranck 7ddac7067d feat: Complete SwiftTUI foundation with overlay system and menu
Core Framework:
- TView protocol with TViewBuilder result builder (up to 10 children)
- Full ANSI rendering pipeline (Terminal, ANSIRenderer, FrameBuffer)
- TApp/TScene/WindowGroup app lifecycle with SIGWINCH handling
- Color system (ANSI, bright, 256-palette, RGB, hex, semantic colors)
- Text styling (bold, italic, underline, strikethrough, dim, blink, inverted)

Container Views:
- VStack, HStack, ZStack with alignment and spacing
- Card (bordered container with padding/background)
- Box (simple bordered container)
- Panel (titled container with title in border)
- ForEach for dynamic content

Modifiers:
- .padding(), .frame(), .border() (8 border styles), .background()
- .overlay() with alignment, .dimmed(), .modal() helper

Overlay System:
- Alert view with title, message, actions, and presets (warning/error/info/success)
- Dialog view for flexible modal content
- FrameBuffer character-level compositing

Menu View:
- Menu with items, selection indicator, shortcuts
- MenuItem model with id, label, shortcut
- AnyView type-erased wrapper

Example App:
- Menu-based navigation with multiple demo pages
- Text Styles, Colors, Containers, Overlays, Layout demos

Tests:
- 58 tests across 12 suites, all passing
2026-01-28 15:35:55 +01:00
phranck dac288a5e4 Initial Commit 2026-01-28 09:26:25 +01:00