Skip to content

feat: migrate TUI layer from React to SolidJS#53

Merged
platypusrex merged 3 commits intomainfrom
refactor/solid-migration
Feb 16, 2026
Merged

feat: migrate TUI layer from React to SolidJS#53
platypusrex merged 3 commits intomainfrom
refactor/solid-migration

Conversation

@platypusrex
Copy link
Contributor

Summary

  • Migrate all TUI components, hooks, and build infrastructure from @opentui/react to @opentui/solid
  • Rewrite rendering layer for Solid's fine-grained reactivity model (run-once components, signals, stores)
  • Fix multiple bugs discovered during migration testing

Changes

Build infrastructure:

  • Swap deps: solid-js, @opentui/solid replacing react, @opentui/react
  • tsconfig.json: jsx: "preserve", jsxImportSource: "@opentui/solid"
  • New build.ts using @opentui/solid/bun-plugin
  • Delete react-compiler.preload.ts

Foundation:

  • ThemeProvider: store-based context (createStore + reconcile) for reactive theme switching through destructured tokens
  • All 6 hooks converted from useState/useEffect/useRef to createSignal/createEffect
  • Signal accessors replace ref-mirror pattern throughout

Components (16 files):

  • All components rewritten for Solid's run-once component model
  • <For>/<Index>/<Show>/<Switch> replace conditional rendering
  • createMemo for derived values (filtered commands, fuzzy search results)
  • <Index> for lists where selection index reactivity matters (theme picker, command menu, file picker)

Bug fixes found during migration:

  • Command menu/file picker: createMemo for filtered lists (component bodies run once)
  • Theme picker: <Index> + store-based ThemeProvider for live preview
  • Tool expand/collapse: extracted ExpandableTool sub-component with <Show> for reactivity
  • Ctrl+E: works during thinking, not just idle
  • Confirmation 'y'/'n' key leak into textarea: defer confirmingToolId clear via queueMicrotask
  • Scroll follow: use ScrollBoxRenderable.scrollTo(idx) (not non-existent scrollToIndex)
  • extractContext: track multi-line oldString end line for correct diff previews

Tracking

Closes #52

Testing

  • Type check: bun check:types passes clean
  • Lint: bun lint — 3 warnings (idiomatic Solid ref={var!}), 8 infos (pre-existing)
  • Manual testing: all features verified across multiple rounds

Migrate all TUI components, hooks, and infrastructure from @opentui/react
to @opentui/solid. This is a complete rewrite of the rendering layer while
preserving all existing functionality.

Build infrastructure:
- Swap deps: solid-js, @opentui/solid replacing react, @opentui/react
- tsconfig: jsx preserve, jsxImportSource @opentui/solid
- New build.ts using @opentui/solid/bun-plugin
- Delete react-compiler.preload.ts

Foundation:
- ThemeProvider: store-based context for reactive theme switching
- All hooks converted from useState/useEffect/useRef to createSignal/createEffect
- Signal accessors replace ref-mirror pattern throughout

Components (16 files):
- All components rewritten for Solid's run-once component model
- <For>/<Index>/<Show>/<Switch> replace conditional rendering
- createMemo for derived values (filteredCommands, fuzzy results)
- <Index> for lists where selection index reactivity matters

Bug fixes found during migration:
- Command menu/file picker: use createMemo for filtered lists
- Theme picker: <Index> + store-based ThemeProvider for live preview
- Tool expand/collapse: extract ExpandableTool with <Show> for reactivity
- Ctrl+E: works during thinking, not just idle
- Confirmation 'y' leak: defer confirmingToolId clear via queueMicrotask
- Scroll follow: use ScrollBoxRenderable.scrollTo(idx)
- extractContext: track multi-line oldString end line for correct diffs
@changeset-bot
Copy link

changeset-bot bot commented Feb 15, 2026

🦋 Changeset detected

Latest commit: 4bbf529

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 1 package
Name Type
olliecode Minor

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

Values computed in Solid component bodies run once and become stale.
Wrap derived data in createMemo so they recompute when dependencies change.

- SessionPicker: projectSessions, groups, flatSessions, sessionIndexMap, scrollHeight
- ThemeProvider: isDark now reactive via createMemo
- Modal: leftOffset, topOffset, modalWidth recompute on terminal resize
- DiffView: diffString, filetype, diffStyle
- AssistantMessage: markdownStyle
- StatusBar: modeColors
- ContextStatsModal: statusColor, statusText, progressColor, ProgressBar bars
- SidePanel: ContextBar filled/empty, ContextSection statusColor,
  TodoSection completed/total/activeTodos/statusColors
- ConfirmingView: deduplicate p().type === 'command' condition
@platypusrex platypusrex merged commit 4756396 into main Feb 16, 2026
1 check passed
@platypusrex platypusrex deleted the refactor/solid-migration branch February 16, 2026 01:14
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[refactor] Migrate TUI from @opentui/react to @opentui/solid

1 participant