public/layout/New-UiTab.ps1

function New-UiTab {
    <#
    .SYNOPSIS
        Creates a tab item within a TabControl, enabling responsive child layouts.
    .PARAMETER Header
        The text label displayed on the tab header.
    .PARAMETER Content
        ScriptBlock containing the tab's child controls.
    .PARAMETER EnabledWhen
        Control name or session variable name that determines when this tab is enabled.
        When the referenced value is truthy, the tab is enabled; when falsy, disabled.
        Supports both control references (e.g., 'showAdvanced') and -Capture variables
        (e.g., 'VCSAConnection') for gated workflows.
    .PARAMETER WPFProperties
        Hashtable of additional WPF properties to set on the control.
        Allows setting any valid WPF property not explicitly exposed as a parameter.
        Invalid properties will generate warnings but not stop execution.
        Supports attached properties using dot notation (e.g., "Grid.Row").
    .EXAMPLE
        New-UiTab -Header "Settings" -EnabledWhen 'isConnected' -Content {
            New-UiInput -Label "Server" -Variable "server"
        }
         
        Creates a tab that is disabled until the 'isConnected' variable is truthy.
    .EXAMPLE
        New-UiTab -Header "Tab" -Content { } -WPFProperties @{
            ToolTip = "Custom tooltip"
            Cursor = "Hand"
            Opacity = 0.8
        }
    #>

    [CmdletBinding()]
    param(
        [Parameter(Mandatory)]
        [string]$Header,
        
        [Parameter(Mandatory)]
        [scriptblock]$Content,

        [Parameter()]
        [object]$EnabledWhen,

        [Parameter()]
        [hashtable]$WPFProperties
    )

    DynamicParam {
        Get-IconDynamicParameter -ParameterName 'Icon'
    }

    begin {
        $Icon = $PSBoundParameters['Icon']
    }

    process {

    $session = Assert-UiSession -CallerName 'New-UiTab'
    $parent  = $session.CurrentParent
    Write-Debug "Header: '$Header', Parent: $($parent.GetType().Name)"

    # logic to find or create TabControl with null safety
    $targetTabControl = $null
    if ($parent -is [System.Windows.Controls.TabControl]) {
        $targetTabControl = $parent
    }
    elseif ($parent -is [System.Windows.Controls.Panel]) {
        foreach ($child in $parent.Children) {
            if ($child -is [System.Windows.Controls.TabControl]) {
                $targetTabControl = $child
                break
            }
        }
    }
    if (!$targetTabControl) {
        $colors = Get-ThemeColors
        $targetTabControl = [System.Windows.Controls.TabControl]@{
            Background      = [System.Windows.Media.Brushes]::Transparent
            BorderBrush     = ConvertTo-UiBrush $colors.Border
            BorderThickness = [System.Windows.Thickness]::new(0, 1, 0, 0)
            Padding         = [System.Windows.Thickness]::new(0)
            Margin          = [System.Windows.Thickness]::new(0, 0, 0, 10)
            TabStripPlacement = 'Top'
        }

        # Use WrapPanel instead of TabPanel to fix multi-row selection behavior
        Set-TabControlStyle -TabControl $targetTabControl

        # Apply center alignment to tab headers if requested
        if ($session.TabAlignment -eq 'Center') {
            # Need to modify the WrapPanel (which holds the tab headers) to center them
            $targetTabControl.Add_Loaded({
                param($sender, $eventArgs)

                # Find the WrapPanel (HeaderPanel) in the visual tree
                $headerPanel = $null
                $queue = [System.Collections.Generic.Queue[System.Windows.Media.Visual]]::new()
                $queue.Enqueue($sender)

                while ($queue.Count -gt 0) {
                    $current = $queue.Dequeue()

                    # Look for WrapPanel with IsItemsHost (our custom template)
                    if ($current -is [System.Windows.Controls.WrapPanel]) {
                        $headerPanel = $current
                        break
                    }
                    # Fallback: also check for TabPanel (default template)
                    if ($current -is [System.Windows.Controls.Primitives.TabPanel]) {
                        $headerPanel = $current
                        break
                    }

                    $childCount = [System.Windows.Media.VisualTreeHelper]::GetChildrenCount($current)
                    for ($i = 0; $i -lt $childCount; $i++) {
                        $child = [System.Windows.Media.VisualTreeHelper]::GetChild($current, $i)
                        $queue.Enqueue($child)
                    }
                }

                # Center the header panel if found
                if ($headerPanel) {
                    $headerPanel.HorizontalAlignment = 'Center'
                }
            })
        }

        Set-ResponsiveConstraints -Control $targetTabControl -FullWidth
        if ($parent -is [System.Windows.Controls.Panel]) { [void]$parent.Children.Add($targetTabControl) }
        elseif ($parent -is [System.Windows.Controls.ItemsControl]) { [void]$parent.Items.Add($targetTabControl) }
        elseif ($parent -is [System.Windows.Controls.ContentControl]) { $parent.Content = $targetTabControl }
    }
    $tabItem = [System.Windows.Controls.TabItem]@{ Header = $Header }
    Set-TabItemStyle -TabItem $tabItem

    # Respect LayoutMode from session
    $layoutMode = if ($session.LayoutMode) { $session.LayoutMode } else { 'Responsive' }

    if ($layoutMode -eq 'Responsive') {
        # WrapPanel enables responsive horizontal wrapping based on available width
        $contentPanel = [System.Windows.Controls.WrapPanel]@{
            HorizontalAlignment = 'Stretch'
            Margin              = [System.Windows.Thickness]::new(10)
        }
    }
    else {
        # Use StackPanel for stack layout
        $contentPanel = [System.Windows.Controls.StackPanel]@{
            Orientation         = 'Vertical'
            HorizontalAlignment = 'Stretch'
            Margin              = [System.Windows.Thickness]::new(10)
        }
    }

    $tabItem.Content = $contentPanel
    $oldParent = $session.CurrentParent
    $session.CurrentParent = $contentPanel
    Write-Debug "Entering content block"

    # Execute content - restore parent outside try/finally for PS 5.1 closure compatibility
    try {
        Invoke-UiContent -Content $Content -CallerName 'New-UiTab' -ErrorAction Stop
    }
    catch {
        # Restore parent before re-throwing
        $session.CurrentParent = $oldParent
        throw
    }
    
    # Restore parent after successful content execution
    $session.CurrentParent = $oldParent
    Write-Debug "Content block complete"

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

    # Wire up conditional enabling if specified
    if ($EnabledWhen) {
        Register-UiCondition -TargetControl $tabItem -Condition $EnabledWhen
    }

    [void]$targetTabControl.Items.Add($tabItem)
    Write-Debug "Tab added to TabControl"
    }
}