public/controls/inputs/New-UiTextArea.ps1

function New-UiTextArea {
    <#
    .SYNOPSIS
        Creates a multi-line text input control.
    .DESCRIPTION
        Creates a TextBox for multi-line entry. A vertical scrollbar appears when the
        text overflows.
    .PARAMETER Label
        Label text displayed above the text area.
    .PARAMETER Variable
        Variable name to store the text value.
    .PARAMETER Default
        Initial text content.
    .PARAMETER Rows
        Number of visible text rows (controls height). Default is 4.
    .PARAMETER Placeholder
        Placeholder/watermark text shown when the text area is empty.
    .PARAMETER Required
        Mark the field as required with an asterisk.
    .PARAMETER ReadOnly
        Makes the text area read-only. Users can select and copy text but not edit it.
    .PARAMETER MaxLength
        Maximum number of characters allowed.
    .PARAMETER FullWidth
        Stretches the control to fill available width instead of fixed sizing.
    .PARAMETER EnabledWhen
        Conditional enabling based on another control's state. Accepts either:
        - A control proxy (e.g., $toggleControl) - enables when that control is truthy
        - A scriptblock (e.g., { $toggle -and $userName }) - enables when expression is true
 
        Truthy values: CheckBox=checked, TextBox=non-empty, ComboBox=has selection.
    .PARAMETER ClearIfDisabled
        When used with -EnabledWhen, clears the text when the control becomes disabled.
    .PARAMETER WPFProperties
        Hashtable of additional WPF properties to set on the control.
    .EXAMPLE
        New-UiTextArea -Label "Description" -Variable "description" -Rows 5 -Placeholder "Enter a detailed description..."
    .EXAMPLE
        New-UiTextArea -Label "Notes" -Variable "notes" -Default "Initial notes here..." -Required
    #>

    [CmdletBinding()]
    param(
        [Parameter(Mandatory)]
        [string]$Label,

        [Parameter(Mandatory)]
        [string]$Variable,

        [string]$Default,

        [int]$Rows = 4,

        [string]$Placeholder,

        [switch]$Required,

        [switch]$ReadOnly,

        [int]$MaxLength,

        [switch]$FullWidth,

        [Parameter()]
        [object]$EnabledWhen,

        [switch]$ClearIfDisabled,

        [Parameter()]
        [hashtable]$WPFProperties
    )

    $session = Assert-UiSession -CallerName 'New-UiTextArea'
    Write-Debug "Creating text area '$Variable' (Rows=$Rows)"
    $colors  = Get-ThemeColors
    $parent  = $session.CurrentParent

    $stack = [System.Windows.Controls.StackPanel]@{
        Margin = [System.Windows.Thickness]::new(4, 4, 4, 8)
    }

    $labelText  = if ($Required) { "$Label *" } else { $Label }
    $labelBlock = [System.Windows.Controls.TextBlock]@{
        Text       = $labelText
        FontSize   = 12
        Foreground = ConvertTo-UiBrush $colors.ControlFg
        Margin     = [System.Windows.Thickness]::new(0, 0, 0, 4)
        Tag        = 'ControlFgBrush'
    }
    [PsUi.ThemeEngine]::RegisterElement($labelBlock)
    [void]$stack.Children.Add($labelBlock)

    # Calculate height based on rows (approximate line height of 20px)
    $lineHeight = 20
    $padding = 8
    $calculatedHeight = ($Rows * $lineHeight) + $padding

    $textArea = [System.Windows.Controls.TextBox]@{
        AcceptsReturn     = $true
        AcceptsTab        = $true
        TextWrapping      = [System.Windows.TextWrapping]::Wrap
        VerticalScrollBarVisibility = [System.Windows.Controls.ScrollBarVisibility]::Auto
        HorizontalScrollBarVisibility = [System.Windows.Controls.ScrollBarVisibility]::Disabled
        MinHeight         = $calculatedHeight
        Height            = $calculatedHeight
        VerticalContentAlignment = [System.Windows.VerticalAlignment]::Top
        Padding           = [System.Windows.Thickness]::new(2, 2, 2, 0)
    }

    if ($Default) {
        $textArea.Text = $Default
    }

    if ($MaxLength -gt 0) {
        $textArea.MaxLength = $MaxLength
    }

    if ($ReadOnly) {
        $textArea.IsReadOnly = $true
    }

    Set-TextBoxStyle -TextBox $textArea

    # Placeholder overlay (same pattern as New-UiInput)
    if ($Placeholder) {
        $grid = [System.Windows.Controls.Grid]::new()

        $placeholderBlock = [System.Windows.Controls.TextBlock]@{
            Text              = $Placeholder
            FontSize          = 12
            Foreground        = ConvertTo-UiBrush $colors.SecondaryText
            FontStyle         = [System.Windows.FontStyles]::Italic
            IsHitTestVisible  = $false
            Margin            = [System.Windows.Thickness]::new(6, 4, 0, 0)
            VerticalAlignment = [System.Windows.VerticalAlignment]::Top
        }

        if ([string]::IsNullOrEmpty($textArea.Text)) {
            $placeholderBlock.Visibility = 'Visible'
        }
        else {
            $placeholderBlock.Visibility = 'Collapsed'
        }

        # Update visibility on text change
        $textArea.Add_TextChanged({
            param($sender, $eventArgs)
            if ([string]::IsNullOrEmpty($sender.Text)) {
                $placeholderBlock.Visibility = 'Visible'
            }
            else {
                $placeholderBlock.Visibility = 'Collapsed'
            }
        }.GetNewClosure())

        [void]$grid.Children.Add($textArea)
        [void]$grid.Children.Add($placeholderBlock)
        [void]$stack.Children.Add($grid)
        $controlElement = $grid
    }
    else {
        [void]$stack.Children.Add($textArea)
        $controlElement = $textArea
    }

    # Tag wrapper for FormLayout unwrapping in New-UiGrid
    Set-UiFormControlTag -Wrapper $stack -Label $labelBlock -Control $controlElement

    # FullWidth in WrapPanel contexts
    Set-FullWidthConstraint -Control $stack -Parent $parent -FullWidth:$FullWidth

    # Apply custom WPF properties if specified
    if ($WPFProperties) {
        Set-UiProperties -Control $stack -Properties $WPFProperties
    }

    Write-Debug "Adding to parent and registering as '$Variable'"
    [void]$parent.Children.Add($stack)

    # Register control with session using AddControlSafe for thread-safe access
    $session.AddControlSafe($Variable, $textArea)

    if ($EnabledWhen) {
        Register-UiCondition -TargetControl $textArea -Condition $EnabledWhen -ClearIfDisabled:$ClearIfDisabled
    }
}