Skip to content

Conversation

@emmauss
Copy link
Contributor

@emmauss emmauss commented Dec 11, 2025

What does the pull request do?

Adds FlexPanel control, adapted from css's flex container.

This implementation was created by @jp2masa and initially contributed to the Labs library here, AvaloniaUI/Avalonia.Labs#37 . The core team has decided that this would be a good time to move that panel to the core repository.

The following API have been added;

public sealed class FlexPanel : Panel
{
    /// <summary>
    /// Gets or sets the direction of the <see cref="FlexPanel"/>'s main-axis,
    /// determining the orientation in which child controls are laid out.
    /// </summary>
    /// <remarks>
    /// When omitted, it is set to <see cref="FlexDirection.Row"/>.
    /// Equivalent to CSS flex-direction property
    /// </remarks>
    public FlexDirection Direction { get; set; }

    /// <summary>
    /// Gets or sets the main-axis alignment of child items inside a line of the <see cref="FlexPanel"/>.
    /// Typically used to distribute extra free space leftover after flexible lengths and margins have been resolved.
    /// </summary>
    /// <remarks>
    /// When omitted, it is set to <see cref="JustifyContent.FlexStart"/>.
    /// Equivalent to CSS justify-content property.
    /// </remarks>
    public JustifyContent JustifyContent { get; set; }

    /// <summary>
    /// Gets or sets the cross-axis alignment of all child items inside a line of the <see cref="FlexPanel"/>.
    /// Similar to <see cref="JustifyContent"/>, but in the perpendicular direction.
    /// </summary>
    /// <remarks>
    /// When omitted, it is set to <see cref="AlignItems.Stretch"/>.
    /// Equivalent to CSS align-items property.
    /// </remarks>
    public AlignItems AlignItems { get; set; }

    /// <summary>
    /// Gets or sets the cross-axis alignment of lines in the <see cref="FlexPanel"/> when there is extra space. 
    /// Similar to <see cref="AlignItems"/>, but for entire lines.
    /// <see cref="FlexPanel.Wrap"/> property set to <see cref="FlexWrap.Wrap"/> mode
    /// allows controls to be arranged on multiple lines.
    /// </summary>
    /// <remarks>
    /// When omitted, it is set to <see cref="AlignContent.Stretch"/>.
    /// Equivalent to CSS align-content property.
    /// </remarks>
    public AlignContent AlignContent { get; set; }

    /// <summary>
    /// Gets or sets the wrap mode, controlling whether the <see cref="FlexPanel"/> is single-line or multi-line.
    /// Additionally, it determines the cross-axis stacking direction for new lines.
    /// </summary>
    /// <remarks>
    /// When omitted, it is set to <see cref="FlexWrap.NoWrap"/>.
    /// Equivalent to CSS flex-wrap property.
    /// </remarks>
    public FlexWrap Wrap { get; set; }

    /// <summary>
    /// Gets or sets the minimum horizontal spacing between child items or lines,
    /// depending on main-axis direction of the <see cref="FlexPanel"/>.
    /// </summary>
    /// <remarks>
    /// When omitted, it is set to 0.
    /// Similar to CSS column-gap property.
    /// </remarks>
    public double ColumnSpacing { get; set; }

    /// <summary>
    /// Gets or sets the minimum vertical spacing between child items or lines,
    /// depending on main-axis direction of the <see cref="FlexPanel"/>.
    /// </summary>
    /// <remarks>
    /// When omitted, it is set to 0.
    /// Similar to CSS row-gap property.
    /// </remarks>
    public double RowSpacing { get; set; }

    /// <summary>
    /// Defines an attached property to control the initial main-axis size of a specific child in a flex layout.
    /// </summary>
    public static readonly AttachedProperty<FlexBasis> BasisProperty;

    /// <summary>
    /// Defines an attached property to control the cross-axis alignment of a specific child in a flex layout.
    /// </summary>
    public static readonly AttachedProperty<AlignItems?> AlignSelfProperty;

    /// <summary>
    /// Defines an attached property to control the order of a specific child in a flex layout.
    /// </summary>
    public static readonly AttachedProperty<int> OrderProperty;

    /// <summary>
    /// Defines an attached property to control the factor by which a specific child can shrink
    /// along the main-axis in a flex layout.
    /// </summary>
    public static readonly AttachedProperty<double> ShrinkProperty;

    /// <summary>
    /// Defines an attached property to control the factor by which a specific child can grow
    /// along the main-axis in a flex layout.
    /// </summary>
    public static readonly AttachedProperty<double> GrowProperty;
}

/// <summary>
/// Defines the alignment mode of the lines inside a <see cref="FlexPanel"/> along the cross-axis. 
/// </summary>
public enum AlignContent
{
    /// <summary>
    /// Lines are packed toward the start of the container.
    /// </summary>
    FlexStart,
    
    /// <summary>
    /// Lines are packed toward the end of the container.
    /// </summary>
    FlexEnd,
    
    /// <summary>
    /// Lines are packed toward the center of the container
    /// </summary>
    Center,
    
    /// <summary>
    /// Lines are stretched to take up the remaining space.
    /// </summary>
    /// <remarks>
    /// This is the default value.
    /// </remarks>
    Stretch,
    
    /// <summary>
    /// Lines are evenly distributed in the container, with no space on either end.
    /// </summary>
    SpaceBetween,
    
    /// <summary>
    /// Lines are evenly distributed in the container, with half-size spaces on either end.
    /// </summary>
    SpaceAround,
    
    /// <summary>
    /// Lines are evenly distributed in the container, with equal-size spaces between each line and on either end. 
    /// </summary>
    SpaceEvenly
}

public enum AlignItems
{
    /// <summary>
    /// Items are aligned to the cross-axis start margin edge of the line.
    /// </summary>
    FlexStart,

    /// <summary>
    /// Items are aligned to the cross-axis end margin edge of the line.
    /// </summary>
    FlexEnd,

    /// <summary>
    /// Items are aligned to the cross-axis center of the line.
    /// </summary>
    /// <remarks>
    /// If the cross size of the line is less than that of the child item,
    /// it will overflow equally in both directions.
    /// </remarks>
    Center,

    /// <summary>
    /// Items are stretched to fill the cross size of the line.
    /// </summary>
    /// <remarks>
    /// This is the default value.
    /// </remarks>
    Stretch
}

/// <summary>
/// Describes the main-axis alignment of items inside a <see cref="FlexPanel"/> line.
/// </summary>
public enum JustifyContent
{
    /// <summary>
    /// Child items are packed toward the start of the line.
    /// </summary>
    /// <remarks>
    /// This is the default value.
    /// </remarks>
    FlexStart,

    /// <summary>
    /// Child items are packed toward the end of the line.
    /// </summary>
    FlexEnd,

    /// <summary>
    /// Child items are packed toward the center of the line.
    /// </summary>
    /// <remarks>
    /// If the leftover free-space is negative, the child items will overflow equally in both directions.
    /// </remarks>
    Center,

    /// <summary>
    /// Child items are evenly distributed in the line, with no space on either end.
    /// </summary>
    /// <remarks>
    /// If the leftover free-space is negative or there is only a single child item on the line,
    /// this value is identical to <see cref="FlexStart"/>.
    /// </remarks>
    SpaceBetween,

    /// <summary>
    /// Child items are evenly distributed in the line, with half-size spaces on either end.
    /// </summary>
    /// <remarks>
    /// If the leftover free-space is negative or there is only a single child item on the line,
    /// this value is identical to <see cref="Center"/>.
    /// </remarks>
    SpaceAround,

    /// <summary>
    /// Child items are evenly distributed in the line, with equal-size spaces between each item and on either end.
    /// </summary>
    SpaceEvenly
}

/// <summary>
/// Describes the orientation and direction along which items are placed inside the <see cref="FlexPanel"/>
/// </summary>
public enum FlexDirection
{
    /// <summary>
    /// Items are placed along the horizontal axis, starting from the left
    /// </summary>
    /// <remarks>
    /// This is the default value.
    /// </remarks>
    Row,

    /// <summary>
    /// Items are placed along the horizontal axis, starting from the right
    /// </summary>
    RowReverse,

    /// <summary>
    /// Items are placed along the vertical axis, starting from the top
    /// </summary>
    Column,

    /// <summary>
    /// Items are placed along the vertical axis, starting from the bottom
    /// </summary>
    ColumnReverse
}

/// <summary>
/// Describes the wrap behavior of the <see cref="FlexPanel"/>
/// </summary>
public enum FlexWrap
{
    /// <summary>
    /// The <see cref="FlexPanel"/> is single line.
    /// </summary>
    /// <remarks>
    /// This is the default value.
    /// </remarks>
    NoWrap,
    
    /// <summary>
    /// The <see cref="FlexPanel"/> is multi line.
    /// </summary>
    Wrap,
    
    /// <summary>
    /// Same as <see cref="Wrap"/> but new lines are added in the opposite cross-axis direction.
    /// </summary>
    WrapReverse
}

/// <summary>
/// Specifies the initial size of a flex item.
/// </summary>
public readonly struct FlexBasis : IEquatable<FlexBasis>
{
    public double Value { get; }

    public FlexBasisKind Kind { get; }

    /// <summary>
    /// Initializes an instance of <see cref="FlexBasis"/> and sets the value and <see cref="FlexBasisKind"/>
    /// </summary>
    /// <param name="value">The value of the <see cref="FlexBasis"/></param>
    /// <param name="kind">The <see cref="FlexBasisKind">. This determines how the value affects the size of the flex item</see>/></param>
    /// <exception cref="ArgumentException"></exception>
    public FlexBasis(double value, FlexBasisKind kind);

    /// <summary>
    /// Initializes an instance of <see cref="FlexBasis"/> and sets the absolute value
    /// </summary>
    /// <param name="value">The absolute value of the <see cref="FlexBasis"/></param>
    /// <exception cref="ArgumentException"></exception>
    public FlexBasis(double value) ;

    public static FlexBasis Auto { get; }

    public bool IsAuto  { get; }
    
    public bool IsAbsolute { get; }
    
    public bool IsRelative { get; }

    /// <summary>
    /// Converts a string flex-basis value to a <see cref="FlexBasis"/> instance.
    /// </summary>
    /// <param name="str">The value to parse.</param>
    /// <returns></returns>
    public static FlexBasis Parse(string str);
}

What is the current behavior?

What is the updated/expected behavior with this PR?

How was the solution implemented (if it's not obvious)?

Checklist

Breaking changes

Obsoletions / Deprecations

Fixed issues

Fixes #8081

@emmauss emmauss changed the title [Fe]Add Flex Panel [Feature] Add Flex Panel Dec 11, 2025
@emmauss emmauss added enhancement feature needs-api-review The PR adds new public APIs that should be reviewed. labels Dec 11, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement feature needs-api-review The PR adds new public APIs that should be reviewed.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

FlexPanel

2 participants