Commit Graph
280 Commits
Author SHA1 Message Date
phranck d700731777 Fix: TextField expands to fill width, label is accessibility-only
- TextField now expands to fill available width (SwiftUI behavior)
- Label parameter is for accessibility only, not rendered visually
- Use prompt: parameter for placeholder text
- Update example app to use prompt: correctly
- SecureField also expands to fill available width
2026-02-13 16:18:14 +01:00
phranck f8e255da06 Fix: TextField/SecureField use fixed default width, don't auto-expand
TextFields should not automatically expand to fill available width.
They now use a fixed defaultContentWidth (20 chars). Use .frame()
modifier to explicitly set a different width if needed.
2026-02-13 16:18:14 +01:00
phranck 9070f740ae Fix: TextField renders label and respects its width
TextField now properly renders its label before the input field and
subtracts the label width from available space. This prevents the
input field from overflowing when hasExplicitWidth is true.
2026-02-13 16:18:14 +01:00
phranck 8fcb115683 Fix: Make rounded the default appearance in AppearanceRegistry
AppearanceRegistry.all now starts with .rounded instead of .line.
Since ThemeManager starts with currentIndex=0, this ensures the
default appearance is rounded corners as intended.
2026-02-13 16:18:14 +01:00
phranck 55ab4a7ffd Refactor: Make Box internal and simplify container width calculation
- Make Box struct internal (use .border() modifier instead)
- Update example app to use .border() instead of Box
- Simplify resolveContainerWidth to just return content width
- Simplify resolveContainerHeight to just return content height
- Remove auto-expansion logic from containers
- Containers now size to fit their content, not fill available space
- Spacers in HStack still expand correctly to fill remaining space
- Update tests for renamed BorderViaContainerViewTests
2026-02-13 16:18:14 +01:00
phranck 1249c263b3 Chore: Update example app pages
- ContainersPage: Use trackStyle() instead of deprecated progressBarStyle()
- LayoutPage: Simplify Spacer demo section
2026-02-13 16:18:14 +01:00
phranck 35b5a30706 Feat: Add layout helpers for container width/height calculations
- Add hasExplicitHeight flag to RenderContext
- Add forBorderedContent() helper for bordered container context
- Add resolveContainerWidth/Height helpers for container sizing
- Add withAvailableSize() for setting both dimensions at once
- Update ContainerView to subtract padding from available width
- Update NavigationSplitView to use withAvailableSize()
- Fix HStack Spacer expansion to respect hasExplicitWidth
- Update RenderLoop to set both hasExplicitWidth/Height
2026-02-13 16:18:13 +01:00
phranck 8eb8f26781 Refactor: Implement SwiftUI-compatible ToggleStyle API
- Add ToggleStyle protocol matching SwiftUI's pattern
- Add .automatic, .checkbox, .switch built-in styles
- Add .toggleStyle(_:) view modifier via Environment
- All styles render as [ ]/[x] in TUI (documented constraint)
- Remove old ToggleStyle enum (.toggle/.checkbox)
- Update example app and tests for new API
2026-02-13 16:18:13 +01:00
phranck 0131e2e7f2 Fix: Use persistedFocusID for stable focus in Slider, Stepper, Button, RadioButton
All focusable views now use persistedFocusID from StateStorage instead of
generating a new focusID on each render. This ensures focus tracking
remains stable across re-renders.

- Slider: Use persistedFocusID, dim unfocused arrows (50% opacity)
- Stepper: Use persistedFocusID, dim unfocused arrows (50% opacity)
- Button: Consistent focus indicator with persistedFocusID
- RadioButton: Add pulsing focus indicator when focused
2026-02-13 16:18:13 +01:00
phranck ee25db7202 Feat: Add TextCursor modifier for cursor styling in TextField/SecureField
- Add cursorColor to Palette protocol with HSL-computed values for all SystemPalette presets
- Create TextCursorStyle with shapes (block, bar, underscore) and animations (none, blink, pulse)
- Add .textCursor(_:) View modifier propagating through environment
- Update TextField and SecureField to use cursorColor and respect cursor style
- Add 17 tests for TextCursorStyle
2026-02-13 16:18:13 +01:00
phranck 30bfeb8688 Docs: Sort TrackStyle examples and enum cases alphabetically 2026-02-10 14:19:26 +01:00
phranck c1f507b782 Fix: Correct row width calculation (only subtract border, not padding) 2026-02-10 13:01:37 +01:00
phranck 17d858ca4e Fix: Badge alignment - now correctly right-aligned at row edge 2026-02-10 13:00:28 +01:00
phranck 352093fbe7 Fix: Badges now display in List rows, List fills column width in SplitView
- Badge values are now extracted from BadgeModifier during row extraction
- Added extractBadgeValue() function using Mirror reflection
- ListRow and SelectableListRow now store badge value
- withAvailableWidth() now sets hasExplicitWidth for proper List expansion
2026-02-10 12:58:31 +01:00
phranck 1a328092a6 Fix: Badge displays without parentheses (SwiftUI parity), sidebar width 25 2026-02-10 12:52:20 +01:00
phranck 69bae90dca Fix: Use .badge() modifier for folder unread counts in SplitView demo 2026-02-10 12:50:08 +01:00
phranck 92a6c3e414 Fix: Badges in List rows are now right-aligned 2026-02-10 12:48:25 +01:00
phranck 0dedddca59 Refactor: Remove maxVisibleRows from List and Table (not in SwiftUI API)
List and Table now always fill available height like SwiftUI.
The TUI-specific maxVisibleRows parameter was removed for API parity.
2026-02-10 12:46:09 +01:00
phranck e2acc069fc Fix: List now fills available height like SwiftUI (greedy layout) 2026-02-10 12:41:26 +01:00
phranck f193fd45c8 Fix: Remove maxVisibleRows from SplitView demo Lists for full height 2026-02-10 12:39:44 +01:00
phranck 4bca440acf Fix: NavigationSplitView uses space separator and fixed column widths
TUI-specific changes:
- Separator is now a space instead of vertical line to avoid double borders
- Sidebar (20 chars) and content (30 chars) have fixed widths
- Only the rightmost column adapts to terminal width changes
- Column content is padded to fill the full column width
2026-02-10 12:35:54 +01:00
phranck c7ef9ac004 Fix: NavigationSplitView focus indicator and improve demo with List components 2026-02-10 12:05:49 +01:00
phranck b3a8cb7e5a Feat: Add NavigationSplitView demo to example app 2026-02-10 12:00:29 +01:00
phranck 9b7454c903 Fix: Remove force casts in StepperHandler using type constraints and .zero 2026-02-10 04:10:21 +01:00
phranck f8881f2bc1 Feat: Add clipboard and undo support to TextField
- Fix escape sequence parsing for fast key repeat (read byte-by-byte)
- Ctrl+A: Select all text
- Ctrl+C: Copy selection to system clipboard (pbcopy/xclip)
- Ctrl+X: Cut selection to clipboard
- Ctrl+V: Paste from clipboard (pbpaste/xsel)
- Ctrl+Z: Undo last change (up to 50 states)
- 12 new tests (998 total)
2026-02-10 04:03:16 +01:00
phranck 19586e8ae7 Feat: Add NavigationSplitView with two/three-column layouts
- NavigationSplitView with sidebar/content/detail columns
- NavigationSplitViewVisibility for programmatic column control
- NavigationSplitViewColumn for column identification
- NavigationSplitViewStyle protocol with automatic/balanced/prominentDetail
- Focus section integration: Tab cycles columns, Up/Down within
- Column width modifier: .navigationSplitViewColumnWidth(_:)
- Style modifier: .navigationSplitViewStyle(_:)
- 39 tests across 8 suites (986 total tests)
2026-02-10 02:59:51 +01:00
phranck c1bda23c92 Feat: Add text selection support to TextField and SecureField
- Parse CSI modifier codes (Shift/Alt/Ctrl) in escape sequences
- Add selection state to TextFieldHandler (anchor, range, helpers)
- Implement Shift+Arrow selection keyboard handling
- Render selection with accent background highlight
- Support delete/replace selected text with Backspace/Delete/typing
- Add 41 new tests (14 KeyEvent + 27 TextFieldHandler)
2026-02-09 22:57:22 +01:00
phranck 91aadd40a1 Feat: Add SecureField component for password input
- SecureField with masked display using ● (U+25CF) bullets
- Reuses TextFieldHandler for key input handling
- SwiftUI API parity: init(_:text:) and init(_:text:prompt:)
- Supports .onSubmit() and .disabled() modifiers
- Focus indicator with pulsing vertical bars
- 15 tests for masking behavior and rendering
- Example app page with password validation demo
2026-02-09 22:20:43 +01:00
phranck bc9841cdc9 Feat: Add Slider and Stepper components with TrackStyle refactor
- Slider: Interactive track control with keyboard navigation (arrow keys, +/-, Home/End)
- Stepper: Increment/decrement control with value or custom callbacks
- TrackStyle: Renamed from ProgressBarStyle, shared between ProgressView and Slider
- TrackRenderer: Extracted utility for track rendering
- 59 new tests (892 total), Example app demo pages for both components
2026-02-09 21:52:37 +01:00
phranck 339e5123a1 Refactor: Improve TextField rendering and input responsiveness
- Remove textInputAutocapitalization (not relevant for TUI)
- TextField now has fixed width with horizontal scrolling
- New visual style: background color + focus indicator bars
- Increase frame rate to 30 FPS and process up to 5 events/frame
- Fix Space key handling in ActionHandler (.space instead of .character)
2026-02-09 21:03:21 +01:00
phranck d607fdc831 Feat: Add TextField<Label> generic, ViewBuilder init, and textInputAutocapitalization 2026-02-09 19:15:56 +01:00
phranck b877cb58ae Feat: Add TextField demo page to Example app 2026-02-09 19:05:30 +01:00
phranck c4ca87f70e Feat: Add TextField component with text input, cursor navigation, and onSubmit 2026-02-09 19:01:28 +01:00
phranck f288eb71a4 Chore: Remove unused ansiRegex (dead code after manual parsing optimization) 2026-02-09 18:33:30 +01:00
phranck 2f8b351bfb Perf: Optimize ANSI string operations
Replace regex-based strippedLength and stripped with manual parsing.

Results:
- strippedLength: 2-5x faster
- stripped: 5-12x faster
- padToVisibleWidth: 1.8-2.2x faster
- Menu render: 34% faster
- RadioButtonGroup render: 22% faster
2026-02-09 18:33:26 +01:00
phranck bfda38ff0d Perf: Optimize FrameBuffer and Stack rendering
- Add FrameBuffer init with pre-computed width
- Optimize appendVertically/appendHorizontally to avoid redundant width computation
- Single-pass computation in VStack/HStack (was 4+ array traversals)
- Add performance benchmark tests (21 tests)

Results:
- VStack (10 children): 3x faster
- Stack nesting depth 10: 2.3x faster
- Nesting overhead: ~0.002ms per level
2026-02-09 18:19:13 +01:00
phranck 26e667f2dc Feat: Add LazyVStack and LazyHStack with lazy rendering 2026-02-09 17:57:27 +01:00
phranck 7e7ad673ca Refactor: Convert VStack, HStack, ZStack to body: some View pattern 2026-02-09 17:55:22 +01:00
phranck 65418a4d5e Feat: Complete View Architecture Refactor - Phase 6 verification
- Add 13 modifier propagation tests
- All 757 tests pass
- SwiftLint clean (no serious violations)
- Move plan to done/
2026-02-09 17:49:24 +01:00
phranck 4e59a36ba4 Refactor: Convert RadioButtonGroup to body: some View pattern 2026-02-09 12:32:16 +01:00
phranck d9010bab39 Refactor: Convert Button, Toggle, Menu to body: some View pattern 2026-02-09 12:32:16 +01:00
phranck 6a4f6880bc Feat: Add preview button to CodePreview with terminal screenshot overlay
- VStack centers children relative to available width when spacers present
- CodePreview: Add Preview button that shows terminal screenshot
- Smooth fade-in animation with blur backdrop
- ESC or click outside to close
- Caption overlay on image
2026-02-09 02:57:48 +01:00
phranck c0c42e8349 Fix: frame(width:) now properly constrains container views like List
- Add hasExplicitWidth flag to RenderContext
- FlexibleFrameView sets flag when width constraints are specified
- ContainerView expands to fill available width when flag is set
- List calculates row width based on frame constraints
- InsetGroupedListStyle: disable alternating row colors by default
- InsetGroupedListStyle: move row padding into renderRow() so backgrounds extend to borders
2026-02-09 02:26:45 +01:00
phranck 2a67398589 Fix: ContainerView respects frame width constraints 2026-02-09 01:28:28 +01:00
phranck cef2483dbf Feat: Add statusBarSystemItems modifier for theme/appearance toggles 2026-02-09 01:12:06 +01:00
phranck 90017af892 Fix: Remove stderr usage for Linux concurrency safety
The fputs(stderr) call was not concurrency-safe on Linux.
Removed the warning entirely since stub modifiers should be silent.
2026-02-08 23:49:45 +01:00
phranck 12e2645969 Feat: Add selectionDisabled and listRowSeparator modifiers
Phase 4 & 6 of List SwiftUI API Parity:
- .selectionDisabled() prevents row selection in List
- .listRowSeparator() stub with warning (not supported in TUI)
- SelectionDisabledKey environment key
- Visibility and VerticalEdge.Set types for API compatibility
- 11 new tests (738 total)
2026-02-08 23:43:59 +01:00
phranck 4937de4748 Fix: Rename count to intValue to avoid SwiftLint false positive
SwiftLint interpreted `count == 0` as empty_count violation,
but count was an Int variable, not a collection property.
2026-02-08 23:04:32 +01:00
phranck 506c7621e9 Feat: Integrate Section into List rendering (Phase 2c3)
- List now uses SelectableListRow<ID> instead of ListRow<ID> internally
- Section headers/footers are non-selectable (.header/.footer types)
- extractRows() detects SectionRowExtractor and flattens to typed rows
- selectableIndices populated for focus navigation skip logic
- renderRow() skips focus/selection background for headers/footers
- Alternating colors restart per section (sectionContentIndex)
- Added Sendable constraint to List<SelectionValue> for Swift 6
- Section conforms to ListRowExtractor (delegates to content ForEach)
- 10 new integration tests (732 total)
2026-02-08 23:00:59 +01:00
phranck 91ca964d93 Feat: Add Section Integration Foundation (Phase 2c1-2c2)
Foundation for integrating Section headers/footers with List row rendering:

- Create SelectableListRow.swift with ListRowType enum (header/content/footer)
  and SelectableListRow struct for type-safe row classification
- Add FrameBuffer Sendable + Equatable conformance (required for SelectableListRow)
- Enhance ItemListHandler with selectableIndices property to track which rows
  can be selected/focused (for skipping non-selectable headers/footers)
- Implement focus skip-logic in moveFocus() to jump over non-selectable rows
- Update Home/End keys to navigate to first/last selectable row
- Add comprehensive documentation to all new types

This foundation enables Phase 2c3 (List flattening and per-section styling).

All tests passing (722). Build + swiftlint clean.
2026-02-08 23:00:59 +01:00