From 005ff6f85f53a71ae1b4be207652ed830ea419ed Mon Sep 17 00:00:00 2001 From: phranck Date: Fri, 6 Feb 2026 22:01:47 +0100 Subject: [PATCH] plans: Add three implementation plans for View Architecture refactoring Phase 1: ContainerView Refactoring (Low-risk, ~2-3h) - Extract _ContainerViewCore with Renderable - Make ContainerView a simple View with body - Enable modifier support Phase 2: Shared Handlers & Helpers (Moderate, ~4-5h) - FocusableItemListHandler (navigation logic) - SelectionStateManager (selection tracking) - ItemStateRenderer (styling utilities) - renderFocusableContainer() (helper function) Phase 3: List & Table Implementation (Moderate-High, ~14-18h) - Refactor List to use new architecture - Implement Table with same foundation - Both follow Box.swift pattern - Maximum code reuse Each phase gets its own branch and PR. --- plans/open/2026-02-06-imp-containerview.md | 59 ++++++++++++ plans/open/2026-02-06-imp-list-table.md | 95 +++++++++++++++++++ plans/open/2026-02-06-imp-shared-handlers.md | 97 ++++++++++++++++++++ 3 files changed, 251 insertions(+) create mode 100644 plans/open/2026-02-06-imp-containerview.md create mode 100644 plans/open/2026-02-06-imp-list-table.md create mode 100644 plans/open/2026-02-06-imp-shared-handlers.md diff --git a/plans/open/2026-02-06-imp-containerview.md b/plans/open/2026-02-06-imp-containerview.md new file mode 100644 index 0000000..f517111 --- /dev/null +++ b/plans/open/2026-02-06-imp-containerview.md @@ -0,0 +1,59 @@ +# Implementation Plan: ContainerView Refactoring + +## Objective +Refactor `ContainerView` from `body: Never` + `Renderable` pattern to correct `View` pattern with internal `_ContainerViewCore`. + +## Current State +- `ContainerView: View` with `body: Never` +- 400+ lines of rendering logic in `renderToBuffer()` +- Modifiers don't work on ContainerView + +## Target State +- `ContainerView: View` with `body: some View` +- `_ContainerViewCore: View, Renderable` contains all logic +- Modifiers work naturally (`.foregroundColor()`, etc.) +- Environment values propagate to content + +## Implementation Steps + +### Phase 1: Extract _ContainerViewCore +1. Create new private struct `_ContainerViewCore` +2. Copy all properties from ContainerView to _ContainerViewCore +3. Move `renderToBuffer()` logic to _ContainerViewCore +4. Conform _ContainerViewCore to `Renderable` + +### Phase 2: Simplify ContainerView +1. Keep all public initializers on ContainerView +2. Add `body: some View` that creates and returns `_ContainerViewCore` +3. Remove `renderToBuffer()` from ContainerView +4. Verify `ContainerConfig` and `ContainerStyle` helpers still work + +### Phase 3: Testing & Verification +1. Run all tests — verify no breakage +2. Check users: Card, Panel, Alert, Dialog still render correctly +3. Verify modifiers work: test `.foregroundColor()` on ContainerView +4. Test environment propagation to nested content + +### Phase 4: Documentation +1. Update any comments/docs referencing the old pattern +2. Add note about `_ContainerViewCore` being internal implementation detail + +## Success Criteria +- ✅ All 618 tests pass +- ✅ No breaking changes to public API +- ✅ Modifiers work on ContainerView +- ✅ Environment values propagate +- ✅ Code follows Box.swift pattern +- ✅ swiftlint clean + +## Estimated Effort +**Low-risk**, mechanical refactoring. ~2-3 hours. + +## Files Changed +- `Sources/TUIkit/Views/ContainerView.swift` (main) +- Possibly minimal changes to test files if needed + +## Related Plans +- Follows from architectural review (CLAUDE.md updates) +- Foundation for List & Table refactoring +- Prerequisite for proper View modifier support diff --git a/plans/open/2026-02-06-imp-list-table.md b/plans/open/2026-02-06-imp-list-table.md new file mode 100644 index 0000000..0db6c3e --- /dev/null +++ b/plans/open/2026-02-06-imp-list-table.md @@ -0,0 +1,95 @@ +# Implementation Plan: List & Table (Refactored) + +## Objective +Implement List and Table using shared handlers/helpers from Phase 2, with proper View architecture. + +## Current State +- List exists but uses wrong pattern (body: Never + Renderable) +- Table doesn't exist yet +- No shared foundation + +## Target State +- List: Public View with body, private _ListCore with Renderable +- Table: Public View with body, private _TableCore with Renderable +- Both use: FocusableItemListHandler, SelectionStateManager, renderFocusableContainer() +- Both follow Box.swift pattern + +## Implementation Steps + +### Phase 1: Refactor List (Using Shared Components) +1. Create `_ListCore` private struct +2. Replace direct `ListHandler` with `FocusableItemListHandler` +3. Replace ad-hoc selection logic with `SelectionStateManager` +4. Use `renderFocusableContainer()` helper +5. Update public List to have `body: some View` that creates _ListCore +6. Remove `renderToBuffer()` from public List +7. Verify all List tests still pass + +### Phase 2: Implement Table (Using Shared Components) +1. Create `Table: View` +2. Create `_TableCore` private struct with Renderable +3. Use `FocusableItemListHandler` (same navigation as List) +4. Use `SelectionStateManager` (row-based selection) +5. Implement table-specific logic: + - Column parsing and alignment + - ANSI-aware column padding + - Grid rendering (not vertical stack) +6. Create helper: `renderTableGrid()` or use `renderFocusableContainer()` +7. Tests: navigation, selection, column alignment + +### Phase 3: Verify Architecture Consistency +1. Both List and Table follow same pattern: + - Public View with `body: some View` + - Private Core with Renderable + - Use shared handlers/helpers +2. Both support modifiers naturally +3. Environment values propagate correctly +4. Keyboard navigation consistent +5. Selection handling consistent + +### Phase 4: Integration Testing +1. Test List with all modifiers: `.foregroundColor()`, `.padding()`, `.disabled()` +2. Test Table with all modifiers +3. Test environment propagation through ListItem content +4. Test selection state transitions +5. Test keyboard navigation in both +6. Test focus indicator rendering + +### Phase 5: Example Apps & Docs +1. Update ListPage to use new List +2. Create TablePage example +3. Document keyboard navigation +4. Document selection patterns +5. Add code examples to DocC + +## Success Criteria +- ✅ All 618 existing tests pass +- ✅ List tests pass (updated for new pattern) +- ✅ Table tests created and pass (>50 tests) +- ✅ Modifiers work on both List and Table +- ✅ Environment values propagate +- ✅ Zero code duplication between List and Table +- ✅ Both follow Box.swift pattern +- ✅ swiftlint clean +- ✅ No breaking changes to public API + +## Estimated Effort +**Moderate to High**, requires careful implementation. ~6-8 hours for List, ~8-10 hours for Table. + +## Files Changed/Created +- `Sources/TUIkit/Views/List.swift` (refactored) +- `Sources/TUIkit/Views/Table.swift` (new) +- `Tests/TUIkitTests/ListTests.swift` (updated) +- `Tests/TUIkitTests/TableTests.swift` (new) +- `Sources/TUIkitExample/Pages/ListPage.swift` (updated) +- `Sources/TUIkitExample/Pages/TablePage.swift` (new) + +## Dependencies +- Phase 1: ContainerView refactoring ✓ +- Phase 2: Shared handlers/helpers ✓ +- These must be completed first + +## Related Plans +- Uses FocusableItemListHandler, SelectionStateManager, renderFocusableContainer() +- Follows Box.swift pattern +- Final implementation of View Architecture guidelines diff --git a/plans/open/2026-02-06-imp-shared-handlers.md b/plans/open/2026-02-06-imp-shared-handlers.md new file mode 100644 index 0000000..835e8c4 --- /dev/null +++ b/plans/open/2026-02-06-imp-shared-handlers.md @@ -0,0 +1,97 @@ +# Implementation Plan: Shared Focus/Selection Handlers & Helpers + +## Objective +Extract and formalize reusable components needed by both List and Table: +- Focus navigation handler +- Selection state manager +- Item rendering utilities +- Container rendering helper + +## Current State +- List has `ListHandler: Focusable` (focus logic only) +- No shared selection state manager +- No standardized container helper for focusable items +- Rendering patterns ad-hoc per control + +## Target State +- `FocusableItemListHandler` — shared focus/navigation logic +- `SelectionStateManager` — shared selection tracking +- `renderFocusableContainer()` — helper similar to `renderContainer()` +- `ItemStateRenderer` — utilities for styling items based on focus/selection + +## Implementation Steps + +### Phase 1: Create FocusableItemListHandler +1. Create new file: `Sources/TUIkit/Internal/FocusableItemListHandler.swift` +2. Extract from List's `ListHandler`: + - `focusedIndex`, `scrollOffset`, `viewportHeight`, `rowCount` + - `focusUp()`, `focusDown()`, `focusHome()`, `focusEnd()`, `focusPageUp()`, `focusPageDown()` + - `ensureFocusedInView()` +3. Conform to `Focusable` protocol +4. Add proper documentation + +### Phase 2: Create SelectionStateManager +1. Create new file: `Sources/TUIkit/Internal/SelectionStateManager.swift` +2. Generic class: `SelectionStateManager` +3. Properties: + - `binding: Binding?` + - `selectedValue: AnyHashable?` +4. Methods: + - `select(index: Int)` — select by index + - `select(value: SelectionValue)` — select by value + - `isSelected(index: Int) -> Bool` + - `isSelected(value: SelectionValue) -> Bool` +5. Type-erasure utilities for `Binding` → `Binding` + +### Phase 3: Create ItemStateRenderer Utilities +1. Create new file: `Sources/TUIkit/Internal/ItemStateRenderer.swift` +2. Function: `renderItemWithState()` + - Parameters: `content: String`, `isFocused: Bool`, `isSelected: Bool`, `palette: Palette` + - Returns: styled string with background color, etc. +3. Optionally: helper for scroll indicators + +### Phase 4: Create renderFocusableContainer Helper +1. Create new file: `Sources/TUIkit/Internal/FocusableContainerRenderer.swift` +2. Function: `renderFocusableContainer()` + - Similar signature to `renderContainer()` + - Plus: focus handler, selection manager, item renderer + - Returns: `FrameBuffer` +3. Handles: + - Extract rows from content + - Apply focus/selection styling + - Manage scrolling + - Wrap in container with title, border, padding + +### Phase 5: Testing +1. Create unit tests for each handler/manager +2. Test navigation logic (focusUp, focusDown, wrapping, etc.) +3. Test selection state transitions +4. Test item rendering with various focus/selection states + +### Phase 6: Documentation +1. Add doc comments to all new types +2. Document the shared architecture in guides + +## Success Criteria +- ✅ All new components have comprehensive tests +- ✅ No duplication of logic between existing and new code +- ✅ Clean, minimal API surface +- ✅ Ready for List and Table to use +- ✅ swiftlint clean +- ✅ All existing tests still pass (618 tests) + +## Estimated Effort +**Moderate**, requires careful design. ~4-5 hours. + +## Files Created +- `Sources/TUIkit/Internal/FocusableItemListHandler.swift` +- `Sources/TUIkit/Internal/SelectionStateManager.swift` +- `Sources/TUIkit/Internal/ItemStateRenderer.swift` +- `Sources/TUIkit/Internal/FocusableContainerRenderer.swift` +- `Tests/TUIkitTests/FocusableItemListHandlerTests.swift` +- `Tests/TUIkitTests/SelectionStateManagerTests.swift` + +## Related Plans +- Foundation for List & Table implementation +- Uses patterns from ContainerView refactoring +- Enables maximum code reuse