Skip to content

Migrate all events to IObservable<T> for pure reactive architecture#50

Merged
Aaronontheweb merged 1 commit into
devfrom
feature/migrate-events-to-observables
Dec 16, 2025
Merged

Migrate all events to IObservable<T> for pure reactive architecture#50
Aaronontheweb merged 1 commit into
devfrom
feature/migrate-events-to-observables

Conversation

@Aaronontheweb

Copy link
Copy Markdown
Owner

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 → observables
  • SpinnerNode, ConditionalNode, ReactiveLayoutNode: use Subject<Unit>
  • ScrollableContainerNode: migrated with proper subscription management
  • StreamingTextNode: ContentChanged now alias for Invalidated observable

Rendering classes migrated:

  • TextInput: OnSubmitSubmitted, OnDirtyDirty
  • ScrollableContent: OnDirtyDirty, now implements IDisposable

Documentation & guidelines:

  • Added CLAUDE.md establishing architectural principle: no mixing System.Reactive with .NET events
  • Updated docs and tutorials with observable patterns

Migration Guide

Before:

input.Submitted += HandleSubmit;
node.Invalidated += () => RequestRedraw();

After:

input.Submitted
    .Subscribe(HandleSubmit)
    .DisposeWith(Subscriptions);
    
node.Invalidated
    .Subscribe(_ => RequestRedraw())
    .DisposeWith(Subscriptions);

Test plan

  • All 463 existing tests pass
  • Demo project builds and runs correctly
  • Documentation updated with new patterns

Preparatory work for #43

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 Aaronontheweb merged commit a02f67a into dev Dec 16, 2025
7 checks passed
@Aaronontheweb Aaronontheweb deleted the feature/migrate-events-to-observables branch December 16, 2025 17:08
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.
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.

1 participant