Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
4f85d98
fix: improve message block spacing and layout
brandonkachen Nov 10, 2025
d9f1682
tweak: selected item in slash menu has darker background
brandonkachen Nov 8, 2025
361afe2
feat: improve status indicator and completion time display
brandonkachen Nov 8, 2025
3f5d8bc
feat(cli): prevent auto-scroll during user-initiated collapses and add
brandonkachen Nov 8, 2025
e773e7d
Improve CLI scroll UX and refactor timer handling
brandonkachen Nov 10, 2025
6956084
revert: restore str-replace, diff-viewer, and tool-call-item componen…
brandonkachen Nov 10, 2025
1ef50ec
made scroll-to-bottom indicator more clear
brandonkachen Nov 10, 2025
176de8b
revert: restore timerStartTime pattern for message components
brandonkachen Nov 10, 2025
f422c82
refactor: simplify collapse handling with callback wrapper pattern
brandonkachen Nov 10, 2025
b592aeb
fix: remove duplicate abortControllerRef and unused use-message-rende…
brandonkachen Nov 10, 2025
db87e4c
refactor: Extract time formatting utility
brandonkachen Nov 10, 2025
d0697bb
fix: Revert status-indicator to main branch implementation with elaps…
brandonkachen Nov 10, 2025
7e0ada9
refactor: convert isUserCollapsingRef to callback pattern
brandonkachen Nov 10, 2025
e4725e4
refactor: consolidate stream state into single StreamStatus enum
brandonkachen Nov 10, 2025
65d2025
improve: increase scroll indicator touch target with padding
brandonkachen Nov 10, 2025
5238f2b
refactor: move queue preview to separate line
brandonkachen Nov 10, 2025
65ef34d
improve: center queue preview on its line
brandonkachen Nov 10, 2025
5dcc740
feat: embed queue preview in input box top border
brandonkachen Nov 10, 2025
c72e7c5
refactor(cli): extract connection status hook and add state machine t…
brandonkachen Nov 11, 2025
6dfc0a0
refactor: move inline StreamStatus import to top of file
brandonkachen Nov 11, 2025
1584c88
Fix status row gating
brandonkachen Nov 11, 2025
c86c535
Add comprehensive JSDoc and tests for formatElapsedTime utility
brandonkachen Nov 11, 2025
f4ec499
Add connection status indicator and improve CLI hooks
brandonkachen Nov 11, 2025
9409c30
Add spacing between text and tool groups
brandonkachen Nov 11, 2025
a7135fd
Merge branch 'main' into cli-scroll-ux-improvements
brandonkachen Nov 11, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
49 changes: 49 additions & 0 deletions cli/knowledge.md
Original file line number Diff line number Diff line change
Expand Up @@ -360,6 +360,55 @@ The cleanest solution is to use a direct ternary with separate `<text>` elements

**Note:** Helper components like `ConditionalText` are not recommended as they add unnecessary abstraction without providing meaningful benefits. The direct ternary pattern is clearer and easier to maintain.

### Combining ShimmerText with Other Inline Elements

**Problem**: When you need to display multiple inline elements alongside a dynamically updating component like `ShimmerText` (e.g., showing elapsed time + shimmer text), using `<box>` causes reconciliation errors.

**Why `<box>` fails:**

```tsx
// ❌ PROBLEMATIC: ShimmerText in a <box> with other elements causes reconciliation errors
<box style={{ gap: 1 }}>
<text fg={theme.secondary}>{elapsedSeconds}s</text>
<text wrap={false}>
<ShimmerText text="working..." />
</text>
</box>
```

The issue occurs because:
1. ShimmerText constantly updates its internal state (pulse animation)
2. Each update re-renders with different `<span>` structures
3. OpenTUI's reconciler struggles to match up the changing children inside the `<box>`
4. Results in "Component of type 'span' must be created inside of a text node" error

**✅ Solution: Use a Fragment with inline spans**

Instead of using `<box>`, return a Fragment containing all inline elements:

```tsx
// Component returns Fragment with inline elements
if (elapsedSeconds > 0) {
return (
<>
<span fg={theme.secondary}>{elapsedSeconds}s </span>
<ShimmerText text="working..." />
</>
)
}

// Parent wraps in <text>
<text style={{ wrapMode: 'none' }}>{statusIndicatorNode}</text>
```

**Key principles:**
- Avoid wrapping dynamically updating components (like ShimmerText) in `<box>` elements
- Use Fragments to group inline elements that will be wrapped in `<text>` by the parent
- Include spacing as part of the text content (e.g., `"{elapsedSeconds}s "` with trailing space)
- Let the parent component provide the `<text>` wrapper for proper rendering

This pattern works because all elements remain inline within a single stable `<text>` container, avoiding the reconciliation issues that occur when ShimmerText updates inside a `<box>`.

### The "Text Must Be Created Inside of a Text Node" Error

**Error message:**
Expand Down
Loading