// Copyright (c) Microsoft. All rights reserved.
using Harness.ConsoleReactiveFramework;
namespace Harness.ConsoleReactiveComponents;
///
/// Props for .
///
public record TopBottomRuleProps : ConsoleReactiveProps
{
/// Gets the foreground color of the horizontal rules. If null, the default terminal color is used.
public ConsoleColor? Color { get; init; }
}
///
/// A component that renders a top and bottom horizontal rule (─) with children
/// stacked vertically between them.
///
public class TopBottomRule : ConsoleReactiveComponent
{
///
/// Calculates the total height including the top rule, children, and bottom rule.
///
/// The component props containing children.
/// 2 (for the rules) plus the sum of all children heights.
public static int CalculateHeight(TopBottomRuleProps props)
{
int childrenHeight = 0;
foreach (var child in props.Children)
{
childrenHeight += child.BaseProps?.Height ?? 0;
}
// Top rule + children + bottom rule
return 2 + childrenHeight;
}
///
public override void RenderCore(TopBottomRuleProps props, ConsoleReactiveState state)
{
int ruleWidth = props.Width;
string rule = new('─', ruleWidth);
if (props.Color.HasValue)
{
Console.Write(AnsiEscapes.SetForegroundColor(props.Color.Value));
}
// Top rule
Console.Write(AnsiEscapes.MoveCursor(props.Y, props.X));
Console.Write(rule);
// Render children stacked below the top rule
int currentY = props.Y + 1;
if (props.Color.HasValue)
{
Console.Write(AnsiEscapes.ResetAttributes);
}
foreach (var child in props.Children)
{
child.BaseProps = child.BaseProps! with { X = props.X, Y = currentY };
child.Render();
currentY += child.BaseProps.Height;
}
if (props.Color.HasValue)
{
Console.Write(AnsiEscapes.SetForegroundColor(props.Color.Value));
}
// Bottom rule
Console.Write(AnsiEscapes.MoveCursor(currentY, props.X));
Console.Write(rule);
if (props.Color.HasValue)
{
Console.Write(AnsiEscapes.ResetAttributes);
}
}
}