You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Add lettered sub-item indentation and DEFAULT highlighting
Implement proper visual hierarchy for AskUserQuestion multi-select options:
- Indent lettered sub-items (a), b), c)) under numbered questions
- Highlight DEFAULT options with green background and black text
- Document OpenTUI TextNodeRenderable constraints and workarounds
Note: Wrapped lines return to column 0 due to OpenTUI limitations with
inline text rendering. This is documented as a known constraint.
Copy file name to clipboardExpand all lines: cli/knowledge.md
+93-1Lines changed: 93 additions & 1 deletion
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -58,7 +58,7 @@ tmux new-session -d -s test-session 'cd /path/to/codebuff && bun --cwd=cli run d
58
58
59
59
## Migration from Custom OpenTUI Fork
60
60
61
-
**October 2024**: Migrated from custom `CodebuffAI/opentui#codebuff/custom` fork to official `@opentui/react@^0.1.27` and `@opentui/core@^0.1.27` packages. Updated to `^0.1.28` in February 2025.
61
+
**October 2024**: Migrated from custom `CodebuffAI/opentui#codebuff/custom` fork to official `@opentui/react@^0.1.27` and `@opentui/core@^0.1.27` packages. Updated to `^0.1.28` in February 2025.**November 2025**: Upgraded to `0.1.41` to test if TextNodeRenderable constraints were relaxed (they weren't - still have same limitations).
62
62
63
63
**Lost Features from Custom Fork:**
64
64
@@ -604,6 +604,98 @@ This prevents invalid children from reaching `TextNodeRenderable` while preservi
604
604
605
605
**Related**: `cli/src/hooks/use-message-renderer.tsx` ensures toggle headers render within a single `<text>` block for StyledText compatibility.
606
606
607
+
### Using `<text>` vs `<box>` for Container Elements
608
+
609
+
**CRITICAL**: `<text>` elements have strict child requirements and cannot accept arbitrary React elements as direct children.
610
+
611
+
**The Error:**
612
+
```
613
+
Error: TextNodeRenderable only accepts strings, TextNodeRenderable instances, or StyledText instances
614
+
at add (/path/to/TextNode.ts:108:15)
615
+
```
616
+
617
+
**When this occurs:**
618
+
```tsx
619
+
// ❌ WRONG: Passing React fragments/elements directly as children of <text>
- `wrapSegmentsInFragments()` returns `KeyedFragment` elements wrapping content
627
+
- `<text>` expects direct text-renderable children (strings, `<span>`, `<strong>`, etc.)
628
+
- React Fragments are not TextNodeRenderable instances
629
+
- OpenTUI's TextNode cannot process the Fragment wrapper
630
+
631
+
**✅ CORRECT Solution: Use `<box>` for layout, `<text>` for content**
632
+
633
+
```tsx
634
+
// Use <box> as container with paddingLeft style
635
+
<boxstyle={{ paddingLeft: 3 }}>
636
+
<text>
637
+
{wrapSegmentsInFragments(children, 'key-prefix')}
638
+
</text>
639
+
</box>
640
+
```
641
+
642
+
**Why this works:**
643
+
- `<box>` accepts any React elements as children (fragments, boxes, text, etc.)
644
+
- `<box>` supports `paddingLeft` style property for indentation
645
+
- The inner `<text>` properly wraps the text-renderable content
646
+
- Wrapping behavior respects the box's paddingLeft on ALL lines
647
+
648
+
**Key Learnings:**
649
+
650
+
1. **For indentation with paddingLeft**: Use `<boxstyle={{ paddingLeft: N }}>`, NOT `<textstyle={{ paddingLeft: N }}>`
651
+
2. **`<text>` is for text rendering**: It should contain text-renderable elements (strings, spans, etc.)
652
+
3. **`<box>` is for layout**: It can contain any React elements and supports layout styles
653
+
4. **Fragments as children**: Only `<box>` can handle Fragment children; `<text>` cannot
654
+
5. **paddingLeft on wrapped text**: Use `<box>` container to ensure wrapped lines maintain indentation
655
+
656
+
**Pattern for indented text blocks:**
657
+
```tsx
658
+
// ✅ Correct pattern for indented, wrappable text
659
+
<boxstyle={{ paddingLeft: 3 }}>
660
+
<text>
661
+
<span>Line one</span>
662
+
{'\n'}
663
+
<span>Line two</span>
664
+
</text>
665
+
</box>
666
+
```
667
+
668
+
### Markdown Renderer Indentation Limitation
669
+
670
+
**Problem:** When markdown content is rendered as inline elements (strings, `<span>`, etc.) and wrapped in `<text>` by parent components, there's no way to maintain indentation on wrapped lines.
671
+
672
+
**Why we can't use `<box>` with `paddingLeft`:**
673
+
- Markdown renderer returns text-renderable inline elements
674
+
- Parent components wrap output in `<text>{markdownOutput}</text>`
675
+
- `<text>` can only contain text-renderable children (strings, `<span>`, etc.)
676
+
- `<box>` is NOT text-renderable, so returning it from markdown renderer causes:
677
+
```
678
+
Error: TextNodeRenderable only accepts strings, TextNodeRenderable instances, or StyledText instances
679
+
```
680
+
681
+
**Current Solution:**
682
+
- Use manual space prepending for lettered sub-items (e.g., ` a) Option`)
683
+
- First line is indented correctly
684
+
- **Known limitation:** Wrapped lines return to column 0 instead of maintaining indentation
685
+
- This is an acceptable trade-off given OpenTUI's architecture
686
+
687
+
**Example of limitation:**
688
+
```
689
+
a) This is a very long option that wraps to
690
+
the next line but doesn't stay indented
691
+
b) Short option
692
+
```
693
+
694
+
**Why this is acceptable:**
695
+
- The first line indentation still provides visual hierarchy
696
+
- Alternative approaches (returning `<box>` from renderer) violate OpenTUI's rendering constraints
697
+
- Users can still clearly see the structure even with imperfect wrapping
0 commit comments