Skip to content

Conversation

@Aaronontheweb
Copy link
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
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.

2 participants