Migrate all events to IObservable<T> for pure reactive architecture#50
Merged
Merged
Conversation
This is a breaking change that establishes a consistent reactive-only pattern throughout Termina. All .NET events have been replaced with IObservable<T> using System.Reactive Subjects. Changes: - IInvalidatingNode.Invalidated: event Action? -> IObservable<Unit> - TextInputNode: Submitted, TextChanged, Invalidated all use observables - SpinnerNode, ConditionalNode, ReactiveLayoutNode: use Subject<Unit> - ScrollableContainerNode: migrated with proper subscription management - StreamingTextNode: ContentChanged now alias for Invalidated observable - Rendering/TextInput: OnSubmit -> Submitted, OnDirty -> Dirty observables - Rendering/ScrollableContent: OnDirty -> Dirty observable, implements IDisposable Updated consumers: - Demo: StreamingChatViewModel uses .Subscribe().DisposeWith() - Tests: Updated to use .Subscribe() instead of += - Docs: Updated code examples to show observable pattern Added CLAUDE.md establishing architectural principle: no mixing System.Reactive with .NET events. Closes preparatory work for #43
Aaronontheweb
added a commit
that referenced
this pull request
May 18, 2026
Adds WithHighlightedIndex(49) to the Gallery's column 3 so the 100-item fill-height list opens scrolled to item #50 instead of the top -- visually demonstrating pre-selection and scroll-into-view together.
Aaronontheweb
added a commit
that referenced
this pull request
May 18, 2026
* feat(SelectionListNode): add WithHighlightedIndex() for pre-selection SelectionListNode<T> always started highlighting at index 0 with no public way to pre-select an item -- e.g. a wizard edit flow that should re-highlight the user's prior choice. - Add WithHighlightedIndex(int) fluent builder; clamps to the valid range, ignores the call when the list is empty (avoids Math.Clamp throwing on min > max), and calls EnsureVisible() to scroll the pre-selected item into view - 6 new tests covering fluent return, clamping (both ends), the empty-list guard, and scroll-into-view on first render - Document the new method and add it to the API reference table Fixes #203 * demo(Gallery): pre-select item #50 in the fill-height list Adds WithHighlightedIndex(49) to the Gallery's column 3 so the 100-item fill-height list opens scrolled to item #50 instead of the top -- visually demonstrating pre-selection and scroll-into-view together.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
This PR establishes a consistent reactive-only pattern throughout Termina by migrating all .NET events to
IObservable<T>using System.Reactive Subjects.This is a breaking change - consumers using
+=event subscriptions must migrate to.Subscribe().Changes
Interface changes:
IInvalidatingNode.Invalidated:event Action?→IObservable<Unit>Layout nodes migrated:
TextInputNode:Submitted,TextChanged,Invalidated→ observablesSpinnerNode,ConditionalNode,ReactiveLayoutNode: useSubject<Unit>ScrollableContainerNode: migrated with proper subscription managementStreamingTextNode:ContentChangednow alias forInvalidatedobservableRendering classes migrated:
TextInput:OnSubmit→Submitted,OnDirty→DirtyScrollableContent:OnDirty→Dirty, now implementsIDisposableDocumentation & guidelines:
CLAUDE.mdestablishing architectural principle: no mixing System.Reactive with .NET eventsMigration Guide
Before:
After:
Test plan
Preparatory work for #43