feat: add mutable composite component lifecycle contract
- add generic child change events for dynamic composite components - update runtime mount tracking to subscribe through the common contract - cover third-party dynamic composite keybinding theme and context injection
This commit is contained in:
@@ -287,6 +287,39 @@ public sealed class TuiRuntimeInputListenerTests
|
||||
Assert.Equal(1, component.SetThemeCount);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void RuntimeInjectsSharedContextIntoDynamicMutableCompositeChildren()
|
||||
{
|
||||
var terminal = new TestTerminalSession();
|
||||
var theme = new TestTheme("third-party-mutable");
|
||||
var keybindings = KeybindingRegistry.CreateDefault();
|
||||
keybindings.SetUserBinding(TuiKeybindings.InputSubmit, KeyNames.Tab);
|
||||
using var runtime = new TuiRuntime(terminal, new DefaultInputParser(), new CountingRenderer(), keybindings, theme);
|
||||
var composite = new ThirdPartyMutableComposite();
|
||||
var input = new TinyTUI.Components.Input();
|
||||
var themeComponent = new RecordingThemeComponent();
|
||||
var contextComponent = new RecordingRuntimeContextComponent();
|
||||
var submitted = false;
|
||||
|
||||
input.OnSubmitted = _ => submitted = true;
|
||||
runtime.Add(composite);
|
||||
runtime.SetFocus(input);
|
||||
|
||||
runtime.Start();
|
||||
composite.Add(new ThirdPartyComposite(new Box(input), themeComponent, contextComponent));
|
||||
terminal.Receive("\t");
|
||||
composite.Remove(composite.Children[0]);
|
||||
|
||||
Assert.True(submitted);
|
||||
Assert.Same(theme, themeComponent.Theme);
|
||||
Assert.Equal(1, themeComponent.SetThemeCount);
|
||||
Assert.Equal(1, contextComponent.MountedCount);
|
||||
Assert.Equal(1, contextComponent.UnmountedCount);
|
||||
Assert.Same(runtime, contextComponent.LastMountedContext?.Runtime);
|
||||
Assert.Same(theme, contextComponent.LastMountedContext?.Theme);
|
||||
Assert.Same(keybindings, contextComponent.LastMountedContext?.Keybindings);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void RuntimeInjectedEditorKeybindingsReachAutocompleteList()
|
||||
{
|
||||
@@ -618,6 +651,47 @@ public sealed class TuiRuntimeInputListenerTests
|
||||
public IEnumerable<IComponent> GetChildren() => Children;
|
||||
}
|
||||
|
||||
private sealed class ThirdPartyMutableComposite : IMutableCompositeComponent
|
||||
{
|
||||
private readonly List<IComponent> _children = [];
|
||||
|
||||
public event EventHandler<CompositeComponentChildChangedEventArgs>? ChildAdded;
|
||||
|
||||
public event EventHandler<CompositeComponentChildChangedEventArgs>? ChildRemoved;
|
||||
|
||||
public IReadOnlyList<IComponent> Children => _children;
|
||||
|
||||
public void Add(IComponent component)
|
||||
{
|
||||
_children.Add(component);
|
||||
ChildAdded?.Invoke(this, new CompositeComponentChildChangedEventArgs(component));
|
||||
}
|
||||
|
||||
public void Remove(IComponent component)
|
||||
{
|
||||
if (_children.Remove(component))
|
||||
ChildRemoved?.Invoke(this, new CompositeComponentChildChangedEventArgs(component));
|
||||
}
|
||||
|
||||
public IReadOnlyList<string> Render(int width)
|
||||
{
|
||||
var lines = new List<string>();
|
||||
|
||||
foreach (var child in _children)
|
||||
lines.AddRange(child.Render(width));
|
||||
|
||||
return lines;
|
||||
}
|
||||
|
||||
public void Invalidate()
|
||||
{
|
||||
foreach (var child in _children)
|
||||
child.Invalidate();
|
||||
}
|
||||
|
||||
public IEnumerable<IComponent> GetChildren() => _children;
|
||||
}
|
||||
|
||||
private sealed class TestTheme(string name) : ITuiTheme
|
||||
{
|
||||
public string Cursor => $"{name}> ";
|
||||
|
||||
Reference in New Issue
Block a user